Compose 可组合项 - DatePicker、DatePickerDialog

news2024/11/23 7:03:04

一、概念

一般是以对话框的形式呼出,DatePickerDialog 就是对 DatePicker 的一个简单对话框封装。

@Composable
fun DatePicker(
    state: DatePickerState,
    modifier: Modifier = Modifier,
    dateFormatter: DatePickerFormatter = remember { DatePickerFormatter() },
    dateValidator: (Long) -> Boolean = { true },
    title: (@Composable () -> Unit)? = {
        DatePickerDefaults.DatePickerTitle(
            state,
            modifier = Modifier.padding(DatePickerTitlePadding)
        )
    },
    headline: (@Composable () -> Unit)? = {
        DatePickerDefaults.DatePickerHeadline(
            state,
            dateFormatter,
            modifier = Modifier.padding(DatePickerHeadlinePadding)
        )
    },
    showModeToggle: Boolean = true,
    colors: DatePickerColors = DatePickerDefaults.colors(

        todayDateBorderColor = Color.Red        //默认选中的当天日期的边框色

        selectedDayContentColor = Color.Red        //选中的文字颜色

        selectedDayContainerColor  = Color.Red        //选中的填充颜色

    )
)

@Composable
fun DatePickerDialog(
    onDismissRequest: () -> Unit,        //关闭对话框回调
    confirmButton: @Composable () -> Unit,        //确认按钮
    modifier: Modifier = Modifier,
    dismissButton: @Composable (() -> Unit)? = null,        //取消按钮
    shape: Shape = DatePickerDefaults.shape,
    tonalElevation: Dp = DatePickerDefaults.TonalElevation,
    colors: DatePickerColors = DatePickerDefaults.colors(),
    properties: DialogProperties = DialogProperties(usePlatformDefaultWidth = false),        //对话框配置,详见Dialog
    content: @Composable ColumnScope.() -> Unit        //传入一个DatePicker
)

输入模式选择模式

二、基本使用

2.1 获取状态

2.1.1 单个日期选择 rememberDatePickerState()

@Composable
fun rememberDatePickerState(
    @Suppress("AutoBoxing") initialSelectedDateMillis: Long? = null,        //默认选中的日期
    @Suppress("AutoBoxing") initialDisplayedMonthMillis: Long? = initialSelectedDateMillis,        //默认显示的月份
    yearRange: IntRange = DatePickerDefaults.YearRange,        //限制选择的年份范围,如 2000..2100
    initialDisplayMode: DisplayMode = DisplayMode.Picker        //选择模式Picker、输入模式Input
): DatePickerState 

2.1.2 范围日期选择 rememberDateRangePickerState()

@Composable
fun rememberDateRangePickerState(
    @Suppress("AutoBoxing") initialSelectedStartDateMillis: Long? = null,        //起始日期
    @Suppress("AutoBoxing") initialSelectedEndDateMillis: Long? = null,        //结束日期
    @Suppress("AutoBoxing") initialDisplayedMonthMillis: Long? =
        initialSelectedStartDateMillis,        //默认显示的月份(如果起始日期没指定就默认是当月)
    yearRange: IntRange = DatePickerDefaults.YearRange,        //允许选择的年份,如 2000..2100
    initialDisplayMode: DisplayMode = DisplayMode.Picker        //选择模式Picker、输入模式Input
): DateRangePickerState

2.1.3 自定义可选择日期 selectableDates

Compose Material3 1.2.0-alpha02 及其以上版本,提供了一个 selectableDates 参数,可以在其中完全自定义可以选择的日期。

val datePickerState = rememberDatePickerState(
        selectableDates = object : SelectableDates {
            // 禁止选择周末(周六和周日)
            override fun isSelectableDate(utcTimeMillis: Long): Boolean {
                return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    val dayOfWeek = Instant.ofEpochMilli(utcTimeMillis).atZone(ZoneId.of("UTC"))
                        .toLocalDate().dayOfWeek
                    dayOfWeek != DayOfWeek.SUNDAY && dayOfWeek != DayOfWeek.SATURDAY
                } else {
                    val calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC"))
                    calendar.timeInMillis = utcTimeMillis
                    calendar[Calendar.DAY_OF_WEEK] != Calendar.SUNDAY &&
                            calendar[Calendar.DAY_OF_WEEK] != Calendar.SATURDAY
                }
            }

            // 只允许选择2023年以前
            override fun isSelectableYear(year: Int): Boolean {
                return year > 2022
            }
        }
    )

2.2 DatePicker

val datePickerState = rememberDatePickerState()
DatePicker(state = datePickerState)
Text("当前选中日期的时间戳 ${datePickerState.selectedDateMillis ?: "没有选择"}")

2.3 DatePickerDialog

var isOpenDialog by remember { mutableStateOf(false) }
val datePickerState = rememberDatePickerState()
val sdf = remember { SimpleDateFormat("yyy-MM-dd") }

if (isOpenDialog) {
    DatePickerDialog(
        onDismissRequest = { isOpenDialog = false},
        colors = DatePickerDefaults.colors(containerColor = AppColors.White),   //背景色(这个在下面的DatePicker中设置无效)
        confirmButton = {
            Text(
                modifier = Modifier
                    .clickableNoRipple {
                        //拿到的是时间戳,需要格式化
                        val date = datePickerState.selectedDateMillis
                        if (date != null) {
                            onValueChange(sdf.format(date))
                            isDefaultValue = false
                        }
                        isOpenDialog = false
                    },
                text = "确定",
            )
        },
        dismissButton = {
            Text(
                modifier = Modifier.clickableNoRipple { isOpenDialog = false },
                text = "取消"
            )
        }
    ) {
        DatePicker(
            state = datePickerState,
            colors = DatePickerDefaults.colors(
                todayDateBorderColor = AppColors.Primary,   //默认选中的当天日期的边框色
                selectedDayContentColor = AppColors.White,  //选中的文字颜色
                selectedDayContainerColor = AppColors.Primary,  //选中的填充颜色
            )
        )
    }
}

三、封装

3.1 单按钮时间选择对话框

@Preview
@Composable
private fun SingleButtonDatePickerPreView() {
    var value by remember { mutableStateOf("选择时间") }
        SingleButtonDatePickerView(
            value = value,
            onValueChange = { value = it },
        )
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SingleButtonDatePickerView(
    modifier: Modifier = Modifier,
    value: String = "选择时间",
    onValueChange: (String) -> Unit,
    borderColor: Color = AppColors.Hint,
) {
    var isOpenDialog by remember { mutableStateOf(false) }
    var isDefaultValue by remember { mutableStateOf(true) }
    val datePickerState = rememberDatePickerState()
    val sdf = remember { SimpleDateFormat("yyy-MM-dd") }
    Row(
        modifier = modifier
            .height(AppDimens.heightButton)
            .border(
                width = 1.dp,
                color = borderColor,
                shape = RoundedCornerShape(AppDimens.radius)
            )
            .padding(horizontal = AppDimens.paddingContent)
            .clickableNoRipple { isOpenDialog = true },
        verticalAlignment = Alignment.CenterVertically,
        horizontalArrangement = Arrangement.SpaceBetween
    ) {
        Text(
            text = value,
            maxLines = 1,
            color = if(isDefaultValue) AppColors.Hint else AppColors.Black,
            fontSize = AppDimens.textPrimary,
        )
        Icon(
            modifier = Modifier.padding(start = 5.dp),
            imageVector = Icons.Default.CalendarMonth,
            contentDescription = null,
            tint = AppColors.Hint
        )
    }
    if (isOpenDialog) {
        DatePickerDialog(
            onDismissRequest = { isOpenDialog = false},
            colors = DatePickerDefaults.colors(containerColor = AppColors.White),   //背景色(这个在下面的DatePicker中设置无效)
            confirmButton = {
                Text(
                    modifier = Modifier
                        .clickableNoRipple {
                            val date = datePickerState.selectedDateMillis
                            if (date != null) {
                                onValueChange(sdf.format(date))
                                isDefaultValue = false
                            } else {
                                isDefaultValue = true
                            }
                            isOpenDialog = false
                        }
                        .padding(end = 20.dp),
                    text = "确定",
                    color = AppColors.Primary,
                    fontSize = AppDimens.textTitle
                )
            },
            dismissButton = {
                Text(
                    modifier = Modifier
                        .clickableNoRipple {
                            isOpenDialog = false
                        }
                        .padding(end = 20.dp),
                    text = "取消",
                    color = AppColors.textGray,
                    fontSize = AppDimens.textTitle
                )
            }
        ) {
            DatePicker(
                state = datePickerState,
                colors = DatePickerDefaults.colors(
                    todayDateBorderColor = AppColors.Primary,   //默认选中的当天日期的边框色
                    selectedDayContentColor = AppColors.White,  //选中的文字颜色
                    selectedDayContainerColor = AppColors.Primary,  //选中的填充颜色
                )
            )
        }
    }
}

3.2 双按钮时间选择对话框

@Preview
@Composable
private fun TwoButtonDatePickerPreview() {
    var startDate by remember { mutableStateOf("开始时间") }
    var endDate by remember { mutableStateOf("结束时间") }
        TwoButtonDatePickerView(
            startDate = startDate,
            endDate = endDate,
            onStartChange = { startDate = it },
            onEndChange = { endDate = it },
        )
}

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TwoButtonDatePickerView(
    modifier: Modifier = Modifier,
    startDate: String = "开始时间",
    endDate: String = "结束时间",
    onStartChange: (String) -> Unit,
    onEndChange: (String) -> Unit,
    borderColor: Color = AppColors.Hint,
) {
    var isOpenStartDialog by remember { mutableStateOf(false) }
    var isOpenEndDialog by remember { mutableStateOf(false) }
    val startDatePickerState = rememberDatePickerState()
    val endDatePickerState = rememberDatePickerState()
    var isStartDateDefault by remember { mutableStateOf(true) }
    var isEndDateDefault by remember { mutableStateOf(true) }
    val sdf = remember { SimpleDateFormat("yyy-MM-dd") }
    Row(
        modifier = modifier
            .height(AppDimens.heightButton)
            .border(
                width = 1.dp,
                color = borderColor,
                shape = RoundedCornerShape(AppDimens.radius)
            )
            .padding(horizontal = AppDimens.paddingContent),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Text(
            modifier = Modifier.clickableNoRipple { isOpenStartDialog = true },
            text = startDate,
            color = if (isStartDateDefault) AppColors.Hint else AppColors.Black,
            maxLines = 1,
            fontSize = AppDimens.textPrimary
        )
        Icon(
            modifier = Modifier
                .size(25.dp)
                .padding(horizontal = 5.dp),
            painter = painterResource(id = R.drawable.icon_arrow_right),
            contentDescription = null,
            tint = AppColors.Hint
        )
        Text(
            modifier = Modifier.clickableNoRipple { isOpenEndDialog = true },
            text = endDate,
            color = if (isEndDateDefault) AppColors.Hint else AppColors.Black,
            maxLines = 1,
            fontSize = AppDimens.textPrimary
        )
        Icon(
            modifier = Modifier.padding(start = 5.dp),
            imageVector = Icons.Default.CalendarMonth,
            contentDescription = null,
            tint = AppColors.Hint
        )
    }
    if (isOpenStartDialog) {
        DatePickerDialog(
            onDismissRequest = { isOpenStartDialog = false},
            colors = DatePickerDefaults.colors(containerColor = AppColors.White),
            confirmButton = {
                Text(
                    modifier = Modifier
                        .clickableNoRipple {
                            val date = startDatePickerState.selectedDateMillis
                            if (date != null) {
                                onStartChange(sdf.format(date))
                                isStartDateDefault = false
                            } else {
                                isStartDateDefault = true
                            }
                            isOpenStartDialog = false
                        }
                        .padding(end = 20.dp),
                    text = "确定",
                    color = AppColors.Primary,
                    fontSize = AppDimens.textTitle
                )
            },
            dismissButton = {
                Text(
                    modifier = Modifier
                        .clickableNoRipple {
                            isOpenStartDialog = false
                        }
                        .padding(end = 20.dp),
                    text = "取消",
                    color = AppColors.textGray,
                    fontSize = AppDimens.textTitle
                )
            }
        ) {
            DatePicker(
                state = startDatePickerState,
                colors = DatePickerDefaults.colors(
                    todayDateBorderColor = AppColors.Primary,
                    selectedDayContentColor = AppColors.White,
                    selectedDayContainerColor = AppColors.Primary,
                )
            )
        }
    }
    if (isOpenEndDialog) {
        DatePickerDialog(
            onDismissRequest = { isOpenEndDialog = false},
            colors = DatePickerDefaults.colors(containerColor = AppColors.White),
            confirmButton = {
                Text(
                    modifier = Modifier
                        .clickableNoRipple {
                            val date = endDatePickerState.selectedDateMillis
                            if (date != null) {
                                onEndChange(sdf.format(date))
                                isEndDateDefault = false
                            } else {
                                isEndDateDefault = true
                            }
                            isOpenEndDialog = false
                        }
                        .padding(end = 20.dp),
                    text = "确定",
                    color = AppColors.Primary,
                    fontSize = AppDimens.textTitle
                )
            },
            dismissButton = {
                Text(
                    modifier = Modifier
                        .clickableNoRipple {
                            isOpenEndDialog = false
                        }
                        .padding(end = 20.dp),
                    text = "取消",
                    color = AppColors.textGray,
                    fontSize = AppDimens.textTitle
                )
            }
        ) {
            DatePicker(
                state = endDatePickerState,
                colors = DatePickerDefaults.colors(
                    containerColor = AppColors.White,
                    todayDateBorderColor = AppColors.Primary,
                    selectedDayContentColor = AppColors.White,
                    selectedDayContainerColor = AppColors.Primary,
                )
            )
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1832005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

15.编写自动化测试(下)

标题 三、控制测试流程3.1 添加测试参数3.2 并行或连续运行测试3.3 显示函数输出3.4 指定/过滤测试用例名称3.5 忽略某些测试用例3.6 只运行被忽略的测试 四、测试的组织结构4.1 概念引入4.2 测试私有函数4.2 单元测试4.3 集成测试4.4 集成测试中的子模块4.5 二进制crate的集成…

【漏洞复现】畅捷通T+ keyEdit SQL注入漏洞

免责声明: 本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测…

Confluence安装

Confluence安装 1.安装 #下载confluence版本(8.5.11) https://www.atlassian.com/software/confluence/download-archives #修改权限 chmod x atlassian-confluence-8.5.11-x64.bin #执行安装 ./atlassian-confluence-8.5.11-x64.bin按照以下提示输入&…

SD-WAN在教育行业的应用及优势解析

随着教育领域的数字化转型,网络技术的需求变得愈发迫切。作为一种前沿的网络解决方案,SD-WAN正在为教育行业提供强有力的支持。本文将详细探讨SD-WAN在教育行业的应用,并分析其为教育行业带来的众多优势。 实现多校区高效互联 教育机构通常拥…

稳了?L3规模化落地在即,激光雷达公司成首批赢家

作者 | 芦苇 编辑 | 德新 在中国,距L3级自动驾驶的规模化落地,又近了一步。 随着国内试点政策刷新,越来越多的车企在部分市域获得了自动驾驶测试牌照,能上路测试的L3级自动驾驶车辆正在快速增加。 其中一个重要节点是&#xf…

Python基础用法 之 转义字符

将两个字符进⾏转义 表示⼀个特殊的字符 \n ---> 换⾏,回⻋ \t ---> 制表符, tab键 注意: print( end\n): print() 函数中默认有⼀个 end\n, 所以,每个 print 结束之后, 都会输出⼀ 个换行。 未完待续。

Java数据类型及运算符及数组(与C语言对比)

Java和C语言在数据类型大部分相同,但是也有不同 1.新增了byte类型(相当于C语言中把char用作整数一样) 2.然后就是char类型的大小改为了2字节。 3.布尔型改名为boolean而不是bool,且大小没有明确规定,方便进行不同平台之间的移…

使用dev_dbg调试

首先内核要使能两个配置才可以使用。一般内核都是打开的。 CONFIG_DEBUG_FSy CONFIG_DYNAMIC_DEBUGy 当编译选项CONFIG_DYNAMIC_DEBUG打开的时候,在编译阶段,kernel会把所有使用dev_dbg()的信息记录在一个table中,这些信息我们可以从/sys/k…

在线预览多类型文件_全栈

目录 一、下载运行项目 二、项目功能 三、前端项目引用 四、文件预览样式更改 在做项目时经常用到在线预览文件,给大家介绍一个好用的在线预览文件项目。使用技术是后端Java,前端Freemarker模板。 FreeMarker 特别适应与 MVC 模式的 Web 应用&#x…

从“产品的RFM分析”看如何探索“职业方向”

我们在做产品分析时,经常会用到一种方法“产品的RFM分析”,它是一种客户细分和价值评估的常用方法,广泛应用于电子商务、零售和其他众多行业,它可以帮助企业和产品团队更好地理解用户行为,优化营销策略,提升…

解禁日大涨,爱玛科技的投资前景值得信任吗?

6月17日,爱玛迎来6.28亿股、金额超190亿元的解禁,占总股本72.91%。不过,爱玛股价在巨量解禁中反而迎来涨势,因为这部分股票中,创始人张剑持有的限售股数量几乎就占了爱玛总股本的七成。某种意义上,市场认为…

【产品经理】订单处理4-拆单策略

上次讲解了订单的促销策略,本次讲解下订单处理过程中的拆单策略。 订单拆单策略分为自动拆单、手动拆单,拆单时机也分为订单未被审核前拆单、订单审核后因仓库/快递情况的拆单,本次主要讲解订单未被审核前拆单、订单审核后快递超重的拆单&am…

ollama模型CPU轻量化部署

一、定义 ollama 定义环境部署demo加载本地模型方法基本指令关闭开启ollamaollama 如何同时 运行多个模型, 多进程ollama 如何分配gpu修改模型的存储路径 二、实现 ollama 定义 ollama 是llama-cpp 的进一步封装,更加简单易用,类似于docker. 模型网址…

SFNC —— 标准特征命名约定(一)

系列文章目录 SFNC —— 标准特征命名约定(一) 文章目录 系列文章目录1、介绍1.1 约定(Conventions)功能名称和接口(Feature Name and Interface)功能类别(Feature Category)功能级别…

菜单栏(骆驼书)

代码如下: 效果图:

使用宝塔面板部署Django应用(不成功Kill Me!)

使用宝塔面板部署Django应用 文章目录 使用宝塔面板部署Django应用 本地操作宝塔面板部署可能部署失败的情况 本地操作 备份数据库 # 备份数据库 mysqldump -u root -p blog > blog.sql创建requirements # 创建requirements.txt pip freeze > requirements.txt将本项目…

揭示SOCKS5代理服务器列表的重要性

在复杂的网络安全领域中,SOCKS5代理在保护在线活动方面发挥着关键作用。本文深入探讨了SOCKS5代理服务器列表的细节,探讨了它们的应用、优势以及在增强在线安全和隐私方面不可或缺的功能。 一、理解SOCKS5代理服务器列表 作为在客户端和服务器之间进行通…

522. 最长特殊序列 II

题目 给定字符串列表 strs ,返回其中最长的特殊序列的长度。如果最长特殊序列不存在,返回 -1。 特殊序列定义如下:该序列为某字符串独有的子序列(即不能是其他字符串的子序列)。 字符串 s 的子序列可以通过删去字符…

Plonky3和Binius中的Brakedown多项式承诺协议解析及优化(3)

3.2 Expander Graph and Linear-Time Encodable Linear Code 线性时间编码是线性纠错码的一种,核心是扩展图(Expander Graph),如下图所示: Figure 3 Expander Graph Expander Graph是一种具有强连通性的稀疏图&#…

ensp防火墙web密码重置(前提通过console可以登录)

客户电脑是命令行没有用户名直接输入密码就可以登录了,但是web端不知道admin的密码 前两天遇到运维单位的一台防火墙web网页不知道用户名密码,默认的登录不了,但是通过console可以登录命令行,今天就记录下如何通过命令行修改web页…