Android Compose 简易日历

初学Compose肯定要做些东西来熟悉,接下来我来分享我做的一个简易日历。
(最新更新:Android Compose 日期选择器
首先推荐一个网站,Accompanist是一组库,旨在用开发人员通常需要但尚不可用的功能来补充[Jetpack Compose。]。https://google.github.io/accompanist/pager/
协奏曲pager implementation(“com.google.accompanist:accompanist-pager:0.21.3-beta”)

然后是一个库,帮助我们在compose里创建和管理viewmodel

implementation(‘androidx.lifecycle:lifecycle-viewmodel-compose:2.4.0’)

首先日历有年月日,但是我做的这个日历没有年份,你当然也可以自己添加。

image.png

image.png

建一个函数,day就是第几天,selectDay用来判断是否是被点击的那天,然后抛出去一个lambda,处理点击事件,lambda传入的day就是用来说明是第几天。
@Composable
fun Day(day: Int, selectDay: Int, dayClick: (Int) -> Unit) {
    Text(text = day.toString(),
        textAlign = TextAlign.Center,
        color = if (day == selectDay) Color.Red else Color.White,
        modifier = Modifier
            .clickable {
                dayClick(day)
            })
}

然后写月份,首先我们写一个枚举类来定义月份,虽然java.time里有自带的,但是由于版本需要安卓8及以上,所以就自己写了,直接复制里面的内容修改就行。

enum class MonthEnum {
    JANUARY,
    FEBRUARY,
    MARCH,
    APRIL,
    MAY,
    JUNE,
    JULY,
    AUGUST,
    SEPTEMBER,
    OCTOBER,
    NOVEMBER,
    DECEMBER;
    companion object {
        private val enums = values()
        fun of(month: Int): MonthEnum {
            if (month < 1 || month > 12) {
                throw RuntimeException("Invalid value for MonthOfYear: $month")
            }
            return enums[month - 1]
        }
    }
    fun maxLength(): Int {
        return when (this) {
            FEBRUARY -> 29
            APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30
            else -> 31
        }
    }
    fun minLength(): Int {
        return when (this) {
            FEBRUARY -> 28
            APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30
            else -> 31
        }
    }
    fun length(leapYear: Boolean): Int {
        return when (this) {
            FEBRUARY -> if (leapYear) 29 else 28
            APRIL, JUNE, SEPTEMBER, NOVEMBER -> 30
            else -> 31
        }
    }
}

/**
 *@param selectDay 动态更新
 *@param dayClick 点击高亮
 *LazyVerticalGrid是用来写网格列表,GridCells.Fixed(6)就是每行6个
 *month.length(true) 返回月份的天数,true则代表闰年
 */
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun Month(
    month: MonthEnum,
    selectDay: Int,
    dayClick: (Int) -> Unit
) {
    Column(
        modifier = Modifier
            .fillMaxHeight()
            .padding(top = 60.dp)
    ) {
        Text(
            text = month.name,
            modifier = Modifier
//                .background(Color.Red)
                .fillMaxWidth(),
            color = Color.White,
            textAlign = TextAlign.Center
        )
        Log.i(TAG, "Month: ${month.name} ")
        LazyVerticalGrid(cells = GridCells.Fixed(6)) {
            items(month.length(true)) { index ->
                Day(day = index + 1, selectDay, dayClick)
            }
        }
    }
}

接下来是最外层的viewpager,move用于页面切换时需要做的事情
@OptIn(ExperimentalPagerApi::class)
@Composable
fun Calendar(selectDay: Int, move: (Int) -> Unit, dayClick: (Int) -> Unit) {
    //对页面更改做出反应¶
    //每当所选页面发生更改时,都会更新PagerState.currentPage属性。
    val pagerState = rememberPagerState()
    LaunchedEffect(pagerState) {
        // 从读取 currentPage 的快照流中收集
        snapshotFlow { pagerState.currentPage }
            .collect {
                move(it)
            }
    }
    HorizontalPager(
        count = 12, state = pagerState, modifier = Modifier
            .paint(
                painter = painterResource(
                    id = R.drawable.background
                ), contentScale = ContentScale.Crop
            )
            .height(300.dp), verticalAlignment = Alignment.Top
    ) { index ->
        Month(
            month = MonthEnum.of(index + 1),
            selectDay = selectDay,
            dayClick = dayClick
        )
    }
}

最后是用法,selectDay是当前选中的号数,move:因为选择的号数可能是大于切换的下个月份的,导致不高亮显示,所以每次切换时默认高亮显示第一天,最外层lambda是处理day的点击事件。
setContent {
    WeChat_ComposeTheme {
        val viewModel: MainViewModel = viewModel()
        Calendar(selectDay = viewModel.selectDay, move = {
            viewModel.selectDay = 1
        }) {
            viewModel.selectDay = it
        }
    }
}

viewModel类里的selectDay用作动态更新,MutableState 类是一个单一的值持有者,其读取和写入由 Compose 观察,当值发生变化会更新ui。
class MainViewModel : ViewModel() {
    var selectDay by mutableStateOf(1)
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值