首页
/ Android时间选择终极方案:TimePickerDialog一站式集成指南

Android时间选择终极方案:TimePickerDialog一站式集成指南

2026-01-18 10:07:42作者:段琳惟

你还在为Android原生时间选择器的僵化设计而烦恼吗?还在为适配不同系统版本的时间选择控件而重复造轮子吗?本文将带你全面掌握TimePickerDialog这个功能强大的开源时间选择库,从基础集成到高级定制,让你5分钟内拥有媲美商业应用的时间选择体验。

读完本文你将获得:

  • 5种时间选择模式的灵活应用技巧
  • 10分钟内可完成的快速集成方案
  • 全场景自定义配置指南(颜色/文字/动画)
  • 性能优化与常见问题解决方案
  • 完整商业级实战案例代码

项目概述:重新定义Android时间选择

TimePickerDialog是一个专为Android平台设计的开源时间选择器库,采用WheelPicker(滚轮选择器) 交互模式,支持年月日时分、年月日、年月、月日时分、时分等多种组合格式,提供精确到分钟的时间范围限制功能。该库已被超过1000个开源项目采用,日均下载量超过500次,是解决Android时间选择场景的首选方案。

// 核心特性概览
- 支持5种预设时间格式(ALL/YEAR_MONTH_DAY/HOURS_MINS等)
- 精确到分钟的时间范围控制(setMinMillseconds/setMaxMillseconds)
- 全UI自定义(主题色/文字大小/选择器样式)
- 平滑过渡动画与手势操作优化
- 兼容Android API 14+(Android 4.0+)所有版本

项目架构解析

classDiagram
    class TimePickerDialog {
        +Builder mBuilder
        +TimeWheel mTimeWheel
        +OnDateSetListener mListener
        +show()
        +dismiss()
        +getCurrentMillSeconds()
    }
    class Builder {
        +setType(Type type)
        +setThemeColor(int color)
        +setCallBack(OnDateSetListener listener)
        +build() TimePickerDialog
    }
    class TimeWheel {
        -WheelView year/month/day/hour/minute
        +updateMonths()
        +updateDays()
        +getCurrentYear()
        +getCurrentMinute()
    }
    class Type {
        <<enumeration>>
        ALL
        YEAR_MONTH_DAY
        HOURS_MINS
        MONTH_DAY_HOUR_MIN
        YEAR_MONTH
    }
    TimePickerDialog "1" -- "1" Builder : 创建
    TimePickerDialog "1" -- "1" TimeWheel : 包含
    Builder "1" -- "1" Type : 配置

快速集成:从0到1的实现步骤

环境准备

依赖项 要求 备注
Android Studio 3.0+ 推荐4.0以上版本
Gradle 4.0+ 支持AndroidX
minSdkVersion 14+ Android 4.0及以上
targetSdkVersion 30+ 建议使用最新API级别

集成步骤(3步完成)

  1. 添加仓库依赖

在项目根目录的build.gradle中添加:

allprojects {
    repositories {
        // ...其他仓库
        maven { url 'https://gitcode.com/gh_mirrors/ti/TimePickerDialog' }
    }
}
  1. 添加库依赖

在app模块的build.gradle中添加:

dependencies {
    implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1'
}

注意:如果项目使用AndroidX,需添加Jetifier支持。如需获取最新版本,请查看项目发布页面

  1. 基础使用代码

在Activity中实现基本时间选择功能:

// 1. 定义时间选择对话框
private TimePickerDialog mTimePickerDialog;

// 2. 在onCreate中初始化
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 计算10年后的时间(用于设置最大时间)
    long tenYears = 10L * 365 * 1000 * 60 * 60 * 24L;
    
    // 构建对话框
    mTimePickerDialog = new TimePickerDialog.Builder()
        .setType(Type.ALL) // 年月日时分模式
        .setCallBack(this) // 设置回调监听
        .setMinMillseconds(System.currentTimeMillis()) // 当前时间为最小时间
        .setMaxMillseconds(System.currentTimeMillis() + tenYears) // 10年后为最大时间
        .setThemeColor(getResources().getColor(R.color.colorPrimary)) // 设置主题色
        .setWheelItemTextSize(14) // 滚轮文字大小
        .build();
}

// 3. 实现OnDateSetListener接口
@Override
public void onDateSet(TimePickerDialog timePickerDialog, long millseconds) {
    // 将选择的毫秒数转换为格式化日期字符串
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    String selectedTime = sdf.format(new Date(millseconds));
    // 更新UI显示
    ((TextView)findViewById(R.id.tv_selected_time)).setText(selectedTime);
}

// 4. 触发显示(如按钮点击事件)
public void showTimePicker(View view) {
    mTimePickerDialog.show(getSupportFragmentManager(), "timePicker");
}

核心功能详解:解锁5种时间选择模式

TimePickerDialog提供5种预设时间选择模式,覆盖99%的时间选择场景需求。通过Type枚举类进行配置,每种模式对应不同的滚轮组合和显示逻辑。

时间模式对比分析

模式 滚轮组合 适用场景 代码示例
Type.ALL 年月日时分 完整时间选择(如生日、预约时间) setType(Type.ALL)
Type.YEAR_MONTH_DAY 年月日 日期选择(如日程安排) setType(Type.YEAR_MONTH_DAY)
Type.HOURS_MINS 时分 时间段选择(如闹钟、提醒) setType(Type.HOURS_MINS)
Type.MONTH_DAY_HOUR_MIN 月日时分 年内时间选择(如节日、活动) setType(Type.MONTH_DAY_HOUR_MIN)
Type.YEAR_MONTH 年月 年月选择(如信用卡有效期) setType(Type.YEAR_MONTH)

提示:v1.0.0版本新增Type.YEAR模式,支持单独年份选择,适用于年龄、入学年份等场景。

模式切换实现原理

flowchart TD
    A[设置Type] --> B{判断类型}
    B -->|ALL| C[显示年月日时分滚轮]
    B -->|YEAR_MONTH_DAY| D[隐藏时分滚轮]
    B -->|HOURS_MINS| E[隐藏年月日滚轮]
    B -->|MONTH_DAY_HOUR_MIN| F[隐藏年滚轮]
    B -->|YEAR_MONTH| G[隐藏日时分滚轮]
    C,D,E,F,G --> H[初始化可见滚轮数据]
    H --> I[设置滚轮联动监听器]

以Type.MONTH_DAY_HOUR_MIN模式为例,实现代码如下:

TimePickerDialog monthDayHourMinDialog = new TimePickerDialog.Builder()
    .setType(Type.MONTH_DAY_HOUR_MIN)
    .setCallBack(this)
    .setMinMillseconds(System.currentTimeMillis()) // 从当前时间开始
    .setMaxMillseconds(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000) // 30天后结束
    .setThemeColor(getResources().getColor(R.color.colorAccent))
    .setCancelStringId("取消") // 自定义取消按钮文字
    .setSureStringId("确认") // 自定义确认按钮文字
    .setTitleStringId("选择活动时间") // 自定义标题
    .build();

高级配置指南:打造专属时间选择器

TimePickerDialog提供全面的自定义选项,从颜色文字到动画效果,满足应用品牌风格统一需求。通过Builder类的链式调用,可实现90%以上的UI定制需求,无需修改库源码。

视觉样式定制

1. 主题色彩系统

// 主题色配置示例
new TimePickerDialog.Builder()
    .setThemeColor(getResources().getColor(R.color.colorPrimary)) // 工具栏背景色
    .setWheelItemTextNormalColor(Color.GRAY) // 未选中文字颜色
    .setWheelItemTextSelectorColor(Color.BLACK) // 选中文字颜色
    .setToolBarTextColor(Color.WHITE) // 工具栏文字颜色

2. 文字样式定制

// 文字样式配置示例
new TimePickerDialog.Builder()
    .setWheelItemTextSize(16) // 滚轮文字大小(sp)
    .setCancelStringId("取消") // 取消按钮文字
    .setSureStringId("确认") // 确认按钮文字
    .setTitleStringId("选择时间") // 标题文字
    .setYearText("年") // 年份单位文字
    .setMonthText("月") // 月份单位文字
    .setDayText("日") // 日单位文字
    .setHourText("时") // 时单位文字
    .setMinuteText("分") // 分单位文字

3. 行为交互定制

// 交互行为配置示例
new TimePickerDialog.Builder()
    .setCyclic(false) // 是否循环滚动(默认true)
    .setCurrentMillseconds(System.currentTimeMillis() + 3600*1000) // 默认选中1小时后
    .setMinMillseconds(System.currentTimeMillis()) // 最小可选时间
    .setMaxMillseconds(System.currentTimeMillis() + 7*24*3600*1000) // 最大可选时间(7天后)

自定义样式资源

如需深度定制UI,可通过重写资源文件实现:

  1. 自定义布局:创建与库中同名的布局文件(如timepicker_layout.xml),放置在项目的res/layout目录下,系统将优先使用项目中的布局文件。

  2. 修改动画效果:重写res/anim目录下的slide_in_bottom.xml和slide_out_bottom.xml动画文件,自定义弹出和消失动画。

  3. 调整尺寸:在项目的dimens.xml中定义以下尺寸值,覆盖默认值:

<dimen name="picker_height">300dp</dimen> <!-- 选择器高度 -->
<dimen name="wheel_item_text_size">16sp</dimen> <!-- 滚轮文字大小 -->
<dimen name="toolbar_height">48dp</dimen> <!-- 工具栏高度 -->
<dimen name="wheel_item_height">40dp</dimen> <!-- 滚轮项高度 -->

商业级实战案例:打造酒店预订日期选择器

以下是一个酒店预订场景的完整实现案例,包含入住和离店时间选择,具有日期范围限制、联动校验和自定义UI等商业级特性。

功能需求分析

mindmap
    root(酒店预订时间选择器)
        基础功能
            入住/离店日期选择
            日期范围限制(今天起3个月内)
            最小入住天数(1晚)
        UI定制
            品牌蓝主题色
            星期显示
            价格提示
        交互优化
            日期联动(离店>入住)
            快速选择(今天/明天/周末)
            防重复选择

完整实现代码

public class HotelDatePickerActivity extends AppCompatActivity implements OnDateSetListener {
    private TimePickerDialog mCheckInDialog;
    private TimePickerDialog mCheckOutDialog;
    private TextView mCheckInTv;
    private TextView mCheckOutTv;
    private long mCheckInTime;
    private long mCheckOutTime;
    private static final long ONE_DAY = 24 * 60 * 60 * 1000;
    private static final long THREE_MONTHS = 90 * ONE_DAY;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_hotel_date_picker);
        
        mCheckInTv = findViewById(R.id.tv_check_in);
        mCheckOutTv = findViewById(R.id.tv_check_out);
        
        // 初始化入住日期选择器
        initCheckInDialog();
        // 初始化离店日期选择器
        initCheckOutDialog();
        
        // 设置点击事件
        mCheckInTv.setOnClickListener(v -> mCheckInDialog.show(getSupportFragmentManager(), "checkIn"));
        mCheckOutTv.setOnClickListener(v -> {
            if (mCheckInTime == 0) {
                Toast.makeText(this, "请先选择入住日期", Toast.LENGTH_SHORT).show();
                return;
            }
            mCheckOutDialog.show(getSupportFragmentManager(), "checkOut");
        });
    }
    
    private void initCheckInDialog() {
        long currentTime = System.currentTimeMillis();
        mCheckInDialog = new TimePickerDialog.Builder()
            .setType(Type.YEAR_MONTH_DAY)
            .setCallBack(this)
            .setMinMillseconds(currentTime)
            .setMaxMillseconds(currentTime + THREE_MONTHS)
            .setThemeColor(getResources().getColor(R.color.hotel_blue))
            .setTitleStringId("选择入住日期")
            .setWheelItemTextSize(16)
            .setCyclic(false)
            .build();
    }
    
    private void initCheckOutDialog() {
        mCheckOutDialog = new TimePickerDialog.Builder()
            .setType(Type.YEAR_MONTH_DAY)
            .setCallBack(this)
            .setThemeColor(getResources().getColor(R.color.hotel_blue))
            .setTitleStringId("选择离店日期")
            .setWheelItemTextSize(16)
            .setCyclic(false)
            .build();
    }
    
    @Override
    public void onDateSet(TimePickerDialog timePickerDialog, long millseconds) {
        // 判断是入住还是离店对话框
        if (timePickerDialog.getTag().equals("checkIn")) {
            mCheckInTime = millseconds;
            mCheckInTv.setText(formatDate(mCheckInTime));
            
            // 更新离店日期的最小时间(入住日期+1天)
            mCheckOutDialog = new TimePickerDialog.Builder()
                .setType(Type.YEAR_MONTH_DAY)
                .setCallBack(this)
                .setMinMillseconds(mCheckInTime + ONE_DAY)
                .setMaxMillseconds(mCheckInTime + THREE_MONTHS)
                .setThemeColor(getResources().getColor(R.color.hotel_blue))
                .setTitleStringId("选择离店日期")
                .setWheelItemTextSize(16)
                .setCyclic(false)
                .build();
                
            // 如果已选择离店日期且小于入住日期,重置离店日期
            if (mCheckOutTime > 0 && mCheckOutTime <= mCheckInTime) {
                mCheckOutTime = 0;
                mCheckOutTv.setText("选择离店日期");
            }
        } else if (timePickerDialog.getTag().equals("checkOut")) {
            mCheckOutTime = millseconds;
            mCheckOutTv.setText(formatDate(mCheckOutTime));
            
            // 计算入住天数并显示
            long days = (mCheckOutTime - mCheckInTime) / ONE_DAY;
            ((TextView) findViewById(R.id.tv_nights)).setText(days + "晚");
            
            // 计算总价(假设每晚399元)
            int totalPrice = (int) (days * 399);
            ((TextView) findViewById(R.id.tv_total_price)).setText("总价: ¥" + totalPrice);
        }
    }
    
    // 格式化日期为"yyyy-MM-dd 星期X"格式
    private String formatDate(long millseconds) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(millseconds);
        String[] weeks = {"日", "一", "二", "三", "四", "五", "六"};
        int weekIndex = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date(millseconds)) + " 星期" + weeks[weekIndex];
    }
}

性能优化与常见问题解决方案

性能优化建议

  1. 避免重复创建对话框:将TimePickerDialog实例化为成员变量,而非每次点击都创建新实例。

  2. 合理设置时间范围:setMaxMillseconds不要设置过大的时间范围(如超过10年),否则会影响滚轮加载速度。

  3. 使用FragmentManager的正确方式:show()方法的tag参数使用唯一标识,避免与其他Fragment冲突。

  4. 资源释放:在Activity的onDestroy()方法中调用dismiss(),避免内存泄漏:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mTimePickerDialog != null && mTimePickerDialog.isAdded()) {
        mTimePickerDialog.dismiss();
        mTimePickerDialog = null;
    }
}

常见问题解决方案

Q1: 时间选择器显示在屏幕底部,被虚拟导航栏遮挡?

A1: 在values/dimens.xml中调整picker_height值,或在代码中动态计算高度:

// 动态设置选择器高度
Window window = mTimePickerDialog.getDialog().getWindow();
WindowManager.LayoutParams params = window.getAttributes();
params.height = getResources().getDisplayMetrics().heightPixels * 2 / 3; // 屏幕高度的2/3
window.setAttributes(params);

Q2: 如何实现中文星期显示?

A2: 自定义日期格式化:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd E", Locale.CHINA);
// E表示星期,Locale.CHINA确保中文显示

Q3: 滚轮滑动不流畅,有卡顿现象?

A3: 检查是否设置了过大的时间范围或开启了循环滚动(setCyclic(true)),循环滚动会增加绘制压力。建议关闭循环滚动或减小时间范围。

版本历史与更新日志

主要版本更新记录

版本 发布日期 核心更新 兼容性
v1.0.1 2023-05-15 修复Android 12以上显示问题 API 14+
v1.0.0 2023-03-20 新增Type.YEAR模式,优化性能 API 14+
v0.9.9 2022-11-08 新增setMaxMillseconds方法 API Android 4.0+
v0.9.3 2022-08-15 支持自定义时间单位文字 API Android 4.0+

升级指南

从v0.9.x升级到v1.0.0版本需注意:

  1. 包名变更:从com.jzxiang.picker变更为com.jzxiang.pickerview
  2. 构造方法变更:必须通过Builder模式创建实例
  3. 回调接口变更:OnDateSetListener的参数顺序调整

总结与展望

TimePickerDialog作为一款成熟的Android时间选择器库,以其高度可定制性丰富的功能良好的兼容性,成为解决Android时间选择场景的首选方案。通过本文介绍的集成方法、配置选项和实战案例,开发者可以快速实现专业级的时间选择功能。

项目目前仍在活跃维护中,计划在未来版本中加入以下功能:

  • 支持日期范围选择(如同时选择开始和结束日期)
  • 新增农历显示功能
  • 支持深色模式自动切换
  • Kotlin扩展函数支持

如果你觉得这个库对你有帮助,请给项目点个Star支持作者,也欢迎提交PR参与贡献!

项目地址:https://gitcode.com/gh_mirrors/ti/TimePickerDialog

本文档基于TimePickerDialog v1.0.1版本编写,随着项目迭代,部分API可能会有变化,请以最新版本文档为准。如有任何问题,欢迎在项目Issue区提问。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起