我们公司UI设计的界面中要用到一个比较简约的时间选择界面如下图
好像还挺常见的,我在网上搜索,其中发现了一个特别好看的实现 https://github.com/loperSeven/DateTimePicker. 但是是使用AndroidView实现的。而且网上大部分的实现都是使用androidview,难道就没有人用compose实现吗??!!既然没有!!那么就由我来实现吧!
本来想写的,但是有好多,如果有时间之后再补充吧,直接看代码的注释吧(
不出意外,直接全部复制过去再修改一下就可以使用了
@Composable
fun DatePickerColumn(
// 列表
pairList: List<Pair<Int, String>>,
itemHeight: Dp,
itemWidth: Dp? = null,
valueState: MutableState<Int>,
focusColor: Color = MaterialTheme.colors.primary,
unfocusColor: Color = Color(0xFFC5C7CF)
) {
var isInit = false
val dataPickerCoroutineScope = rememberCoroutineScope()
val listState = rememberLazyListState()
var value by valueState
LazyColumn(
state = listState,
modifier = Modifier
.height(itemHeight * 6)
.padding(top = itemHeight / 2, bottom = itemHeight / 2)
) {
item {
Surface(Modifier.height(itemHeight)) {}
}
item {
Surface(Modifier.height(itemHeight)) {}
}
itemsIndexed(items = pairList, key = { index, pair -> pair.first }) { index, pair ->
val widthModifier = itemWidth?.let { Modifier.width(itemWidth) } ?: Modifier
Box(
modifier = Modifier
.height(itemHeight)
.then(widthModifier)
.clickable {
dataPickerCoroutineScope.launch {
listState.animateScrollToItem(index = index)
}
}
.padding(start = 5.dp, end = 5.dp), Alignment.Center
) {
Text(
text = pair.second, color =
if (listState.firstVisibleItemIndex == index) focusColor
else unfocusColor
)
}
}
item {
Surface(Modifier.height(itemHeight)) {}
}
item {
Surface(Modifier.height(itemHeight)) {}
}
}
/**
* Jetpack Compose LazyColumn的滑动开始、结束及进行中事件
* 参考文章 https://blog.csdn.net/asd912756674/article/details/122544808
*/
if (listState.isScrollInProgress) {
LaunchedEffect(Unit) {
//只会调用一次,相当于滚动开始
}
//当state处于滚动时,preScrollStartOffset会被初始化并记忆,不会再被更改
val preScrollStartOffset by remember { mutableStateOf(listState.firstVisibleItemScrollOffset) }
val preItemIndex by remember { mutableStateOf(listState.firstVisibleItemIndex) }
val isScrollDown = if (listState.firstVisibleItemIndex > preItemIndex) {
//第一个可见item的index大于开始滚动时第一个可见item的index,说明往下滚动了
true
} else if (listState.firstVisibleItemIndex < preItemIndex) {
//第一个可见item的index小于开始滚动时第一个可见item的index,说明往上滚动了
false
} else {
//第一个可见item的index等于开始滚动时第一个可见item的index,对比item offset
listState.firstVisibleItemScrollOffset > preScrollStartOffset
}
DisposableEffect(Unit) {
onDispose {
// 滑动结束时给状态赋值,并自动对齐
value = pairList[listState.firstVisibleItemIndex].first
dataPickerCoroutineScope.launch {
listState.animateScrollToItem(listState.firstVisibleItemIndex)
}
}
}
}
// 选择初始值
LaunchedEffect(Unit) {
var initIndex = 0
for (index in pairList.indices) {
if (value == pairList[index].first) {
initIndex = index
break
}
}
dataPickerCoroutineScope.launch {
listState.animateScrollToItem(initIndex)
}
}
}
@Preview(heightDp = 500)
@Composable
fun DataTimePicker(
date: Date = Date()
) {
val itemHeight = 50.dp
Box(
modifier = Modifier
.wrapContentHeight()
.fillMaxWidth(),
Alignment.Center
) {
Row(
Modifier
.wrapContentHeight()
.fillMaxWidth()
.background(MaterialTheme.colors.surface),
Arrangement.SpaceEvenly,
Alignment.CenterVertically
) {
val year = date.getYearr()
val selectYear = rememberSaveable { mutableStateOf(year) }
val years = LinkedList<Pair<Int, String>>().apply {
for (i in year downTo 1980) {
add(Pair(i, "${i}年"))
}
}
DatePickerColumn(years, itemHeight, 70.dp, selectYear)
// 月份
val month = date.getMonthh()
val selectMonth = rememberSaveable { mutableStateOf(month) }
val months = ArrayList<Pair<Int, String>>(12).apply {
for (i in 1..12) {
add(Pair(i, "${i}月"))
}
}
DatePickerColumn(months, itemHeight, 50.dp, selectMonth)
// 月份的天数
val dayOfMon = date.getDayOfMonth()
val selectDay = rememberSaveable { mutableStateOf(dayOfMon) }
val dayCountOfMonth = DateUtil.getDayCountOfMonth(selectYear.value, selectMonth.value)
// 提前定义好
val day31 = ArrayList<Pair<Int, String>>().apply {
for (i in 1..31)
add(Pair(i, "${i}日"))
}
val day30 = ArrayList<Pair<Int, String>>().apply {
for (i in 1..30)
add(Pair(i, "${i}日"))
}
val day29 = ArrayList<Pair<Int, String>>().apply {
for (i in 1..29)
add(Pair(i, "${i}日"))
}
val day28 = ArrayList<Pair<Int, String>>().apply {
for (i in 1..28)
add(Pair(i, "${i}日"))
}
// 快速切换
val dayOfMonList = when (dayCountOfMonth) {
28 -> day28
29 -> day29
30 -> day30
else -> day31
}
DatePickerColumn(
pairList = dayOfMonList,
itemHeight = itemHeight,
valueState = selectDay
)
// 小时
val hour = date.getHour()
val selectHour = rememberSaveable { mutableStateOf(hour) }
val hours = ArrayList<Pair<Int, String>>(24).apply {
for (i in 0..23) {
add(Pair(i, "${i}时"))
}
}
DatePickerColumn(hours, itemHeight, 50.dp, selectHour)
// 分
val minute = date.getMinute()
val selectMinute = rememberSaveable { mutableStateOf(minute) }
val minutes = ArrayList<Pair<Int, String>>(60).apply {
for (i in 0..59) {
add(Pair(i, "${i}分"))
}
}
DatePickerColumn(minutes, itemHeight, 50.dp, selectMinute)
// 秒
val second = date.getSecond()
val selectSecond = rememberSaveable { mutableStateOf(second) }
val seconds = ArrayList<Pair<Int, String>>(60).apply {
for (i in 0..59) {
add(Pair(i, "${i}秒"))
}
}
DatePickerColumn(seconds, itemHeight, 50.dp, selectSecond)
}
// 放在后面使得不会被遮住
Column {
Divider(
Modifier.padding(
start = 15.dp,
end = 15.dp,
bottom = itemHeight
),
thickness = 1.dp
)
Divider(
Modifier.padding(
start = 15.dp,
end = 15.dp
),
thickness = 1.dp
)
}
}
}
import java.text.SimpleDateFormat
import java.util.*
fun Date.getFormatString(pattern: String = "yyyy-MM-dd HH:mm:ss"): String {
val sdf = SimpleDateFormat(pattern, Locale.CHINA)
return sdf.format(this)
}
fun Date.getYearr(): Int {
val calendar = GregorianCalendar()
calendar.time = this
return calendar.get(Calendar.YEAR)
}
fun Date.getMonthh(): Int {
val calendar = GregorianCalendar()
calendar.time = this
// 月份从0开始,需要手动 +1
return calendar.get(Calendar.MONTH) + 1
}
fun Date.getDayOfMonth(): Int {
val calendar = GregorianCalendar()
calendar.time = this
return calendar.get(Calendar.DAY_OF_MONTH)
}
fun Date.getHour(): Int {
val calendar = GregorianCalendar()
calendar.time = this
return calendar.get(Calendar.HOUR_OF_DAY)
}
fun Date.getMinute(): Int {
val calendar = GregorianCalendar()
calendar.time = this
return calendar.get(Calendar.MINUTE)
}
fun Date.getSecond(): Int {
val calendar = GregorianCalendar()
calendar.time = this
return calendar.get(Calendar.SECOND)
}
fun Date.plusDays(days: Int = 1): Date {
val calendar = GregorianCalendar()
calendar.time = this
calendar.add(Calendar.DATE, days)
return calendar.time
}
fun Date.minusDays(days: Int = 1): Date {
val calendar = GregorianCalendar()
calendar.time = this
calendar.add(Calendar.DATE, -days)
return calendar.time
}
class DateUtil {
companion object {
fun getDayCountOfMonth(year: Int, month: Int): Int {
if (month == 2) {
//判断年是不是闰年
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
return 29
} else {
return 28
}
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30
} else
return 31
}
}
}
不好意思,我不知道怎么录制GIF图(X,想看效果直接复制代码看看吧
不知道为什么,点击lazyColumn中子项的滑动事件有时候不生效,求解答