效果图
首先放一张最终的效果图
git地址
https://github.com/AigeStudio/WheelPicker
WheelPicker引入
首先我们需要在对应的build.gradle引入这个库
implementation 'cn.aigestudio.wheelpicker:WheelPicker:1.1.3'
layout使用(附代码)
在这一步已经可以直接在layout文件中使用,观看一下效果后再根据自己的需求去调整。
这里我就直接上我写好的代码。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/pop_up_background_color"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/tvCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="@dimen/item_dp_28"
android:text="@string/cl_common_cancel"
android:textColor="@color/text_main_body_color"
android:textSize="@dimen/sp_14" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:textColor="@color/tv_title_dark_grey"
android:textSize="@dimen/sp_17" />
<TextView
android:id="@+id/tvConfirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="@dimen/item_dp_28"
android:text="@string/cl_common_confirm"
android:textColor="@color/text_special_color"
android:textSize="@dimen/sp_14" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingBottom="@dimen/dp_24"
android:paddingStart="@dimen/dp_16"
android:paddingEnd="@dimen/dp_16">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:text="Y"
android:textSize="@dimen/sp_15"
android:textColor="@color/text_special_color"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="M"
android:textSize="@dimen/sp_15"
android:textColor="@color/text_special_color"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="D"
android:textSize="@dimen/sp_15"
android:textColor="@color/text_special_color"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="H"
android:textSize="@dimen/sp_15"
android:textColor="@color/text_special_color"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="M"
android:textSize="@dimen/sp_15"
android:textColor="@color/text_special_color"
android:gravity="center"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
android:textSize="@dimen/sp_15"
android:textColor="@color/text_special_color"
android:gravity="center"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingLeft="@dimen/dp_16"
android:paddingRight="@dimen/dp_16"
android:paddingBottom="@dimen/dp_48">
<com.aigestudio.wheelpicker.widgets.WheelYearPicker
android:id="@+id/wpYear"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
app:wheel_item_text_size="@dimen/sp_15"
app:wheel_item_text_color="@color/text_main_body_color"
app:wheel_indicator="true"
app:wheel_indicator_size="@dimen/dp_1"
app:wheel_indicator_color="@color/text_main_body_color"
app:wheel_visible_item_count="5"
app:wheel_item_space="@dimen/dp_16"
app:wheel_atmospheric="true"/>
<com.aigestudio.wheelpicker.widgets.WheelMonthPicker
android:id="@+id/wpMonth"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_item_text_size="@dimen/sp_15"
app:wheel_item_text_color="@color/text_main_body_color"
app:wheel_indicator="true"
app:wheel_indicator_size="@dimen/dp_1"
app:wheel_indicator_color="@color/text_main_body_color"
app:wheel_visible_item_count="5"
app:wheel_item_space="@dimen/dp_16"
app:wheel_atmospheric="true"/>
<com.aigestudio.wheelpicker.widgets.WheelDayPicker
android:id="@+id/wpDay"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_item_text_size="@dimen/sp_15"
app:wheel_item_text_color="@color/text_main_body_color"
app:wheel_indicator="true"
app:wheel_indicator_size="@dimen/dp_1"
app:wheel_indicator_color="@color/text_main_body_color"
app:wheel_visible_item_count="5"
app:wheel_item_space="@dimen/dp_16"
app:wheel_atmospheric="true"/>
<com.aigestudio.wheelpicker.WheelPicker
android:id="@+id/wpHour"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_item_text_size="@dimen/sp_15"
app:wheel_item_text_color="@color/text_main_body_color"
app:wheel_indicator="true"
app:wheel_indicator_size="@dimen/dp_1"
app:wheel_indicator_color="@color/text_main_body_color"
app:wheel_visible_item_count="5"
app:wheel_item_space="@dimen/dp_16"
app:wheel_atmospheric="true"/>
<com.aigestudio.wheelpicker.WheelPicker
android:id="@+id/wpMinute"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:wheel_item_text_size="@dimen/sp_15"
app:wheel_item_text_color="@color/text_main_body_color"
app:wheel_indicator="true"
app:wheel_indicator_size="@dimen/dp_1"
app:wheel_indicator_color="@color/text_main_body_color"
app:wheel_visible_item_count="5"
app:wheel_item_space="@dimen/dp_16"
app:wheel_atmospheric="true"/>
<com.aigestudio.wheelpicker.WheelPicker
android:id="@+id/wpNoon"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.5"
app:wheel_item_text_size="@dimen/sp_15"
app:wheel_item_text_color="@color/text_main_body_color"
app:wheel_indicator="true"
app:wheel_indicator_size="@dimen/dp_1"
app:wheel_indicator_color="@color/text_main_body_color"
app:wheel_visible_item_count="5"
app:wheel_item_space="@dimen/dp_16"
app:wheel_atmospheric="true"/>
</LinearLayout>
</LinearLayout>
我这里是使用了6个WheelPicker
其中的 颜色文件color 和 占宽比重 大家可以根据自己的需求去定,下面我对部分代码进行详解:
// 这个是选中item的上下两根线,true为显示,false为去掉
app:wheel_indicator="true"
//size是线的粗线
app:wheel_indicator_size="@dimen/dp_1"
//color是线的颜色
app:wheel_indicator_color="@color/text_main_body_color"
//这个是总共显示的item数
app:wheel_visible_item_count="5"
//两个item之间间隔的距离
app:wheel_item_space="@dimen/dp_16"
//是否加入渐变色,这里会按照你设置的item文字颜色,越靠近两边颜色越淡
app:wheel_atmospheric="true"
WheelPicker的Data设置
这里的年月日是使用了WheelPicker自带的年月日picker,所以Data已经自动设置为年份和月份还有天数的对应数据。
至于后面的Hour、Minute、AM or PM这个的数据则需要我们自己写入
//初始化Hour数据 (0-11)
val listOfHour = (0..11).map { number ->
if (number < 10) "0$number" else number.toString()
}
wpHour.data = listOfHour
//初始化Minute数据 (0-59)
val listOfMinute = (0..59).map { number ->
if (number < 10) "0$number" else number.toString()
}
wpMinute.data = listOfMinute
//初始化noon
wpNoon.data = listOf("AM", "PM")
如果大家不想写AM、PM这一栏也可以直接在Hour处使用 0-23 来显示
Select的初始值设置
我们在设置完所有对应的data后,其实就已经和效果图的展示一样了。
但是我们正常使用的时候是需要带参去初始化显示,去给它赋一个值来显示,下面就是我给它赋值的一个过程。
首先我写了个带所有需要使用到的参数的方法
// 传入日期时间设置
fun setInitialDateTime(year: Int, month: Int, day: Int, hour: Int, minute: Int, isAM: Boolean) {
//初始化Hour数据
val listOfHour = (0..12).map { number ->
if (number < 10) "0$number" else number.toString()
}
wpHour.data = listOfHour
//初始化Minute数据
val listOfMinute = (0..59).map { number ->
if (number < 10) "0$number" else number.toString()
}
wpMinute.data = listOfMinute
//初始化noon
wpNoon.data = listOf("AM", "PM")
//设置年份
wpYear.selectedYear = year
//设置月份
wpMonth.selectedMonth = month
//设置天
wpDay.month = month
wpDay.selectedDay = day
//设置小时
wpHour.setSelectedItemPosition(hour,false)
//设置分钟
wpMinute.setSelectedItemPosition(minute,false)
//设置早上晚上
wpNoon.setSelectedItemPosition(if (isAM) 0 else 1, false)
}
将一个指定的字符串,(例:2024/04/24 16:18) 传入,这里可以获取当前的时间去传入,就可以显示当前的日期和时间。
//填充默认时间
val currentDateTime = Calendar.getInstance()
val year = currentDateTime.get(Calendar.YEAR)
val month = currentDateTime.get(Calendar.MONTH) + 1
val day = currentDateTime.get(Calendar.DAY_OF_MONTH)
val hour = currentDateTime.get(Calendar.HOUR_OF_DAY)
val minute = currentDateTime.get(Calendar.MINUTE)
val formattedDateTime = String.format("%04d/%02d/%02d %02d:%02d", year, month, day, hour, minute)
这里我是因为在界面上有显示对应时间,所以仅在第一次进入界面初始化的时候去拿了当前时间使用,后面都是用的选择后的时间(因为我在点击确认后就会显示新的选中时间)。
val formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm")
val dateTime = LocalDateTime.parse(str, formatter)
val mDateSelectDialog = CustomDateSelectDialog(activity as AppCompatActivity)
val year = dateTime.year
val month = dateTime.monthValue
val day = dateTime.dayOfMonth
var hour = dateTime.hour
var isAm = true
if (hour > 12) {
isAm = false
hour -= 12
}
val minute = dateTime.minute
mDateSelectDialog.setInitialDateTime(year,month,day,hour,minute,isAm)
mDateSelectDialog.setTouchOutSide(true)
mDateSelectDialog.setConfirmFilterListener {
csiDate.setRightText(it, false)
}
输出选中的时间
这里因为我是做成一个popupWindow,也就是弹出框的形式,所以我在确定编辑数据后还会将它以一个字符串的形式返回到界面显示。
//点击确认按钮
tvConfirm.setOnClickListener {
//确认最终编辑的数据
val selYear = wpYear.currentYear
val selMonth = wpMonth.currentMonth
val selDay = wpDay.currentDay
var selHour = wpHour.currentItemPosition
val selMinute = wpMinute.currentItemPosition
val isAM = wpNoon.currentItemPosition == 0
if (!isAM) {
selHour += 12
}
val dateStr = String.format("%04d/%02d/%02d %02d:%02d", selYear, selMonth, selDay, selHour, selMinute)
}
这里拿到最终的dateStr数据进行显示就可以了,我在这里是写了个回调在后面,与这篇的内容关系不大,在这里就不写上了,大家自己根据数据进行处理就好。
小结
完成了UI设计图所需的日期时间选择器效果,写个笔记顺便可以记录和复盘一下过程。