# android 时间选择器 **Repository Path**: nnddkj/android-time-selector ## Basic Information - **Project Name**: android 时间选择器 - **Description**: android 时间选择器 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-16 - **Last Updated**: 2026-08-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # TimePicker 时间选择器 Library > 一个开箱即用、功能齐全、商业级的 Android 时间选择器通用库。 > 支持年、月、日、时、分、秒 任意组合选择,提供多种展示方式与丰富的定制能力, > 复制即可在任意新项目中直接使用。 **开发者:宁工** --- ## 目录 1. [特性亮点](#一特性亮点) 2. [工程结构](#二工程结构) 3. [引入方式](#三引入方式) 4. [快速开始(Kotlin)](#四快速开始kotlin) 5. [Java 调用方式](#五java-调用方式) 6. [配置项详解](#六配置项详解) 7. [展示方式](#七展示方式) 8. [主题系统](#八主题系统) 9. [时间范围与禁用限制](#九时间范围与禁用限制) 10. [时间格式转换工具](#十时间格式转换工具) 11. [权限工具(兼容各版本)](#十一权限工具兼容各版本) 12. [MVVM 架构中使用](#十二mvvm-架构中使用) 13. [兼容性说明](#十三兼容性说明) 14. [混淆配置](#十四混淆配置) 15. [Demo 测试工程](#十五demo-测试工程) --- ## 一、特性亮点 - ✅ **6 个时间单位任意组合**:年、月、日、时、分、秒,可自由配置显示哪些(如只选日期、只选时间、年月日时分、全部显示等) - ✅ **4 种商业主流展示方式**:底部弹窗(最常用)、居中对话框、下拉/上拉弹窗、内嵌 View - ✅ **3 种文字显示风格**:普通数字 / 补零 / 带单位后缀 - ✅ **4 种主题**:浅色 / 深色 / 跟随系统 / 自定义颜色 - ✅ **丰富定制**:文本颜色、选中颜色、字体大小、行高、可见行数、标题、按钮文字等 - ✅ **范围限制**:最小时间、最大时间、禁用时间段、仅允许时间段、禁用星期几 - ✅ **智能联动**:大小月/闰年自动处理,滚轮自动吸附最近合法时间 - ✅ **商业级交互**:惯性滚动、平滑回弹、选中放大、渐变遮罩、禁用项置灰 - ✅ **时间格式转换工具**:10+ 常用格式、相对时间、日期计算、线程安全 - ✅ **权限工具**:自动兼容 Android 6.0+ 运行时权限,Java/Kotlin 双支持 - ✅ **Java / Kotlin 双支持**:Builder 链式配置,两语言均可直接调用 - ✅ **兼容 Android 5.0(API 21)~ Android 17(API 37)** - ✅ **纯 UI 库,零权限依赖**,与 MVVM/常规架构均无缝兼容 --- ## 二、工程结构 ``` TimeDemo/ ├── app/ # Demo 测试工程(演示 Library 的所有用法) │ └── src/main/java/com/nyw/timedemo/ │ ├── MainActivity.kt # 主演示页(内嵌/弹窗/样式/范围/权限) │ ├── FormatToolsActivity.kt # 时间格式转换工具演示 │ └── JavaExampleActivity.java # 纯 Java 调用演示 │ └── timelibrary/ # ★ 时间选择器 Library(复制此目录到新项目即可) └── src/main/java/com/nyw/picker/ ├── WheelView.kt # 滚轮核心控件(惯性滚动/缩放/禁用) ├── TimePickerView.kt # 组合选择器(多滚轮联动+范围校正) ├── TimePickerConfig.kt # 配置类(Builder 模式) ├── TimePicker.kt # 统一入口(门面) ├── TimePickerDialog.kt # 居中对话框 ├── TimePickerBottomSheet.kt # 底部弹窗 ├── TimePickerPopup.kt # 下拉/上拉弹窗 ├── TimePickerContainer.kt # 复用容器(标题栏+选择器) ├── TimeUnits.kt # 时间单位标志位 ├── PickerTheme.kt # 主题 ├── DisplayStyle.kt # 显示风格 ├── TimeRange.kt # 时间段模型 ├── TimeSelectModel.kt # 选择结果模型 ├── OnTimeSelectListener.kt # 选择完成回调 ├── OnTimeChangeListener.kt # 实时变化回调 └── util/ ├── TimeFormatUtils.kt # 时间格式转换工具 └── PermissionUtils.kt # 权限工具 ``` --- ## 三、引入方式 ### 方式一:模块依赖(推荐,源码级) 将 `timelibrary` 目录复制到你的工程根目录,然后: **`settings.gradle.kts`** 添加: ```kotlin include(":app") include(":timelibrary") ``` **app 模块 `build.gradle.kts`** 添加依赖: ```kotlin dependencies { implementation(project(":timelibrary")) } ``` ### 方式二:AAR 依赖 ```kotlin dependencies { implementation(files("libs/timelibrary-release.aar")) } ``` > AAR 可在 `timelibrary/build/outputs/aar/` 目录找到(执行 `gradlew :timelibrary:assembleRelease` 生成)。 --- ## 四、快速开始(Kotlin) ### 1. 底部弹窗(最常用,一行代码) ```kotlin import com.nyw.picker.* // 默认配置(年月日时分秒,浅色主题) TimePicker.showBottomSheet(this, TimePicker.defaultConfig()) { time -> val str = time.format("yyyy-MM-dd HH:mm:ss") // 任意格式回调 textView.text = str } ``` ### 2. 完整自定义配置 ```kotlin val config = TimePicker.builder() .setShowType(TimeUnits.TYPE_YMD_HMS) // 显示:年月日时分秒 .setTheme(PickerTheme.light()) // 主题:浅色 .setTitle("选择时间") // 标题 .setDisplayStyle(DisplayStyle.PADDING_ZERO) // 文字:补零(01月01日) .setTextSize(18f) // 字体大小 sp .setItemHeight(48) // 行高 dp .setVisibleItemCount(7) // 可见行数 .setFormat("yyyy-MM-dd HH:mm:ss") // 回调格式 .setDefaultTime(System.currentTimeMillis()) // 默认选中时间 .setMinTime(...) // 最小时间 .setMaxTime(...) // 最大时间 .build() TimePicker.showBottomSheet(this, config) { time -> textView.text = time.format(config.formatPattern) } ``` ### 3. 内嵌到布局中 **XML 布局:** ```xml app:tp_dark="false" app:tp_primaryColor="#3D7EFF" /> ``` **代码:** ```kotlin val picker = TimePicker.createView(this, config) // 或 findViewById(R.id.picker) picker.setConfig(config) picker.setOnTimeChangeListener { time -> // 实时回调 tvPreview.text = time.format("yyyy-MM-dd HH:mm:ss") } picker.setOnTimeSelectListener { time -> // 确认回调 tvResult.text = time.format("yyyy-MM-dd HH:mm:ss") } // 手动触发确认: picker.confirm() ``` --- ## 五、Java 调用方式 Library 完全支持 Java 调用,API 与 Kotlin 一致。 ```java import com.nyw.picker.*; // 1. 底部弹窗 TimePickerConfig config = new TimePickerConfig.Builder() .setShowType(TimeUnits.TYPE_YMD_HMS) .setTitle("选择时间") .setTheme(PickerTheme.light()) .setFormat(TimeFormatUtils.PATTERN_YMD_HMS) .build(); TimePicker.showBottomSheet(this, config, new OnTimeSelectListener() { @Override public void onTimeSelect(@NonNull TimeSelectModel time) { String str = time.format(TimeFormatUtils.PATTERN_YMD_HMS); textView.setText(str); } }); // 2. 居中对话框(仅日期) TimePicker.showDialog(this, new TimePickerConfig.Builder() .setShowType(TimeUnits.TYPE_YMD) .build(), time -> { textView.setText(time.format(TimeFormatUtils.PATTERN_YMD)); }); // 3. 内嵌 View TimePickerView picker = TimePicker.createView(this, config); container.addView(picker); ``` > 更多 Java 示例见 Demo 工程的 `JavaExampleActivity.java`。 --- ## 六、配置项详解 | 配置方法 | 说明 | 默认值 | | --- | --- | --- | | `setShowType(int)` | 显示哪些时间单位(TimeUnits 标志位,任意组合) | 全部 | | `setTheme(PickerTheme)` | 主题(浅色/深色/跟随系统/自定义) | 浅色 | | `setTitle(String)` | 弹窗标题 | "选择时间" | | `setCancelText(String)` | 取消按钮文字 | "取消" | | `setConfirmText(String)` | 确定按钮文字 | "确定" | | `setTextColor(int)` | 滚轮普通文字颜色 | 主题默认 | | `setSelectedTextColor(int)` | 滚轮选中文字颜色 | 主题默认 | | `setTextSize(float)` | 字体大小(sp) | 17 | | `setItemHeight(int)` | 滚轮单行高度(dp) | 48 | | `setVisibleItemCount(int)` | 滚轮可见行数(自动转奇数) | 7 | | `setCyclic(boolean)` | 是否循环滚动 | false | | `setMinTime(long)` | 最小可选时间(毫秒时间戳) | 不限 | | `setMaxTime(long)` | 最大可选时间(毫秒时间戳) | 不限 | | `setDefaultTime(long)` | 默认选中时间(毫秒时间戳,0=当前) | 当前时间 | | `addDisabledRange(TimeRange)` | 添加禁用时间段 | 无 | | `setDisabledRanges(List)` | 设置禁用时间段列表 | 无 | | `addEnabledRange(TimeRange)` | 添加仅允许时间段(非空时只允许这些段) | 无 | | `setEnabledRanges(List)` | 设置仅允许时间段列表 | 无 | | `setDisabledWeekDays(int...)` | 禁用星期几(1=周日...7=周六) | 无 | | `setDisplayStyle(DisplayStyle)` | 文字风格(普通/补零/带后缀) | 补零 | | `setFormat(String)` | 回调时间格式 | yyyy-MM-dd HH:mm:ss | | `setCancelable(boolean)` | 点击遮罩是否可关闭 | true | | `setShowToolbar(boolean)` | 是否显示工具栏 | true | ### 显示单位(TimeUnits)常用组合 | 常量 | 值 | 显示 | | --- | --- | --- | | `TimeUnits.TYPE_YEAR` | 1 | 年 | | `TimeUnits.TYPE_MONTH` | 2 | 月 | | `TimeUnits.TYPE_YEAR_MONTH` | 3 | 年月 | | `TimeUnits.TYPE_YMD` | 7 | 年月日 | | `TimeUnits.TYPE_HM` | 24 | 时分 | | `TimeUnits.TYPE_HMS` | 56 | 时分秒 | | `TimeUnits.TYPE_YMD_HM` | 31 | 年月日时分 | | `TimeUnits.TYPE_YMD_HMS` | 63 | 年月日时分秒 | 任意组合:`TimeUnits.YEAR or TimeUnits.HOUR`(只显示 年 和 小时)。 ### 显示风格(DisplayStyle) ```kotlin DisplayStyle.NORMAL // 2026 1 1 12 5 5 DisplayStyle.PADDING_ZERO // 2026 01 01 12 05 05(默认) DisplayStyle.WITH_SUFFIX // 2026年 01月 01日 12时 05分 05秒 ``` --- ## 七、展示方式 ### 1. 底部弹窗 `TimePickerBottomSheet`(商业 App 最常用) ```kotlin TimePicker.showBottomSheet(context, config) { time -> ... } // 或 TimePickerBottomSheet.show(context, config, listener) ``` ### 2. 居中对话框 `TimePickerDialog` ```kotlin TimePicker.showDialog(context, config) { time -> ... } // 或 TimePickerDialog.show(context, config, listener) ``` ### 3. 下拉/上拉弹窗 `TimePickerPopup` ```kotlin // 锚点下方(默认) TimePicker.showPopup(anchorView, config) { time -> ... } // 锚点上方 TimePicker.showPopup(anchorView, config, listener, null, TimePickerPopup.AnchorPosition.ABOVE) ``` ### 4. 内嵌 View `TimePickerView` ```kotlin val picker = TimePicker.createView(context, config) // 或直接放入 XML 布局 ``` ### 实时变化监听 ```kotlin picker.setOnTimeChangeListener { time -> tv.text = time.format("yyyy-MM-dd HH:mm:ss") // 滚动过程中实时刷新 } ``` --- ## 八、主题系统 ```kotlin // 浅色主题(默认) PickerTheme.light() // 深色主题(暗黑模式场景) PickerTheme.dark() // 跟随系统(自动浅色/深色切换) PickerTheme.auto() // 自定义主题 PickerTheme.custom( primaryColor = 0xFF9C27B0.toInt(), // 强调色(确认按钮、选中高亮) backgroundColor = 0xFFFFFFFF.toInt(), // 背景色 toolbarColor = 0xFFF7F8FA.toInt(), // 工具栏背景 textColor = 0xFF1B1B1B.toInt(), // 主文本 subTextColor = 0xFF6B6B6B.toInt(), // 次级文本 wheelNormalColor = 0xFF9E9E9E.toInt(),// 滚轮普通项 wheelSelectedColor = 0xFF1B1B1B.toInt(), // 滚轮选中项 wheelDisabledColor = 0xFFD0D0D0.toInt(), // 滚轮禁用项 dividerColor = 0xFFEEEEEE.toInt() // 分割线 ) ``` --- ## 九、时间范围与禁用限制 ```kotlin val config = TimePicker.builder() .setShowType(TimeUnits.TYPE_YMD_HM) // 1. 最小/最大时间 .setMinTime(TimeFormatUtils.getTodayStart()) // 今天 00:00 起 .setMaxTime(TimeFormatUtils.getDayEnd(cal.timeInMillis)) // 30 天后 23:59 止 // 2. 禁用某时间段(明天 10:00 ~ 12:00 不可选) .addDisabledRange(TimeRange.create( TimeFormatUtils.getDayStart(tomorrow) + TimeFormatUtils.parseTimeOfDay("10:00"), TimeFormatUtils.getDayStart(tomorrow) + TimeFormatUtils.parseTimeOfDay("12:00") )) // 3. 禁用星期(周末不可选) .setDisabledWeekDays(Calendar.SUNDAY, Calendar.SATURDAY) // 4. 仅允许某些时间段(例如仅工作日 9:00~18:00) // .addEnabledRange(TimeRange.create(...)) .build() ``` **TimeRange 便捷创建:** ```kotlin TimeRange.create(startMillis, endMillis) // 时间戳 TimeRange.create("2026-01-01 00:00:00", "2026-01-02 00:00:00") // 字符串 TimeRange.dayOf("2026-01-01") // 某整天 TimeRange.timeRangeOf("2026-01-01", "09:00", "12:00") // 某天某时段 ``` > 滚动到禁用项时自动吸附到最近的合法时间,禁用项置灰显示。 --- ## 十、时间格式转换工具 `TimeFormatUtils` 提供线程安全的时间格式转换能力: ```kotlin // 格式化 TimeFormatUtils.formatTimestamp(millis, "yyyy-MM-dd HH:mm:ss") // 常用格式常量 TimeFormatUtils.PATTERN_YMD_HMS // yyyy-MM-dd HH:mm:ss TimeFormatUtils.PATTERN_YMD // yyyy-MM-dd TimeFormatUtils.PATTERN_HMS // HH:mm:ss TimeFormatUtils.PATTERN_YMD_HMS_CN // yyyy年MM月dd日 HH:mm:ss TimeFormatUtils.PATTERN_ISO // yyyy-MM-dd'T'HH:mm:ss TimeFormatUtils.PATTERN_COMPACT // yyyyMMddHHmmss // ... 共 13 种常用格式 // 解析 TimeFormatUtils.safeParse("2026-01-01 12:30:00") // -> Long TimeFormatUtils.parseToMillis(text, pattern) // 相对时间 TimeFormatUtils.getRelativeTime(millis) // 刚刚 / x分钟前 / x小时前 / 昨天 / 日期 // 日期计算 TimeFormatUtils.getTodayStart() / getTodayEnd() TimeFormatUtils.getDayStart(millis) / getDayEnd(millis) TimeFormatUtils.getWeekStart(millis) / getWeekEnd(millis) TimeFormatUtils.getMonthStart(millis) / getMonthEnd(millis) TimeFormatUtils.getYearStart(millis) / getYearEnd(millis) TimeFormatUtils.isLeapYear(2024) TimeFormatUtils.getDaysInMonth(2026, 2) TimeFormatUtils.getWeekName(millis) // 星期一... TimeFormatUtils.getAge(birthdayMillis) // 年龄 TimeFormatUtils.isToday(millis) TimeFormatUtils.diffDays(a, b) ``` --- ## 十一、权限工具(兼容各版本) `PermissionUtils` 封装了 Activity Result API,自动兼容所有安卓版本 (API 23 以下直接授权,无需处理 onRequestPermissionsResult): ```kotlin // 请求单个权限 PermissionUtils.request(activity, Manifest.permission.CAMERA) { granted -> if (granted) { ... } else { ... } } // 请求多个权限 PermissionUtils.requestMultiple(activity, arrayOf( Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO )) { results, allGranted -> ... } // 检查权限 PermissionUtils.checkPermission(context, permission) // 带解释说明的请求(用户拒绝过时先弹说明) PermissionUtils.requestWithRationale(activity, permission, "需要相机权限用于扫码") { granted -> ... } // 跳转应用设置 PermissionUtils.goToAppSettings(context) // 常用权限常量 PermissionUtils.CAMERA / RECORD_AUDIO / ACCESS_FINE_LOCATION / READ_CONTACTS ... PermissionUtils.storagePermission() // 自动适配 Android 13+ 细粒度存储权限 ``` > 注意:宿主 App 需在 Manifest 中声明所需权限(Library 为纯 UI 库,不主动声明)。 --- ## 十二、MVVM 架构中使用 在 MVVM 架构中完全兼容,选择结果通过回调驱动 ViewModel 即可: ```kotlin // ViewModel 中定义 class OrderViewModel : ViewModel() { private val _selectedTime = MutableLiveData() val selectedTime: LiveData = _selectedTime fun onTimeSelected(model: TimeSelectModel) { _selectedTime.value = model } } // Activity/Fragment 中 viewModel.selectedTime.observe(this) { time -> // 更新 UI / 提交请求 tv.text = time.format("yyyy-MM-dd HH:mm:ss") } TimePicker.showBottomSheet(this, config) { time -> viewModel.onTimeSelected(time) } ``` --- ## 十三、兼容性说明 | 项目 | 说明 | | --- | --- | | 最低版本 | Android 5.0(API 21) | | 最高版本 | Android 17(API 37) | | 依赖 | appcompat 1.6+、core-ktx 1.10+、activity 1.8+、material 1.10+ | | 权限 | 纯 UI 库,无任何强制权限 | | 架构 | 兼容 MVC / MVP / MVVM / 协程等任何架构 | | 语言 | Kotlin / Java 均可调用 | --- ## 十四、混淆配置 Library 已内置 `consumer-rules.pro`(跟随 AAR 自动生效), 如单独使用源码模块,在 app 的 proguard 规则中添加: ```proguard -keep class com.nyw.picker.** { *; } -keep interface com.nyw.picker.** { *; } -keep enum com.nyw.picker.** { *; } ``` --- ## 十五、Demo 测试工程 `app` 模块为完整的测试工程,运行即可查看 Library 全部效果: - **内嵌式选择器**:实时联动年月日时分秒 - **底部弹窗** / **居中对话框** / **下拉弹窗** - **仅选日期 / 仅选时间 / 年月日时分** - **深色主题 / 自定义样式**(紫色、大字号、带后缀) - **范围限制**(min/max + 禁用周末 + 禁用时间段) - **时间格式转换工具页** - **Java 调用示例页** - **权限请求示例** --- ## License 本 Library 由 **宁工** 开发可自由使用。 在找工作,有内推就好了,广州或深圳最好了,欢迎介绍 如有问题或建议,欢迎交流反馈。