Compose 可组合项 - DatePicker、DatePickerDialog

一、概念

一般是以对话框的形式呼出,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,
                )
            )
        }
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JSR303校验

校验的需求 前端请求后端接口传输参数,需要校验参数。 在controller中需要校验参数的合法性,包括:必填项校验、数据格式校验等在service中需要校验业务规则,比如:课程已经审核过了,所以提交失败。 servi…

面料识别技术:AI如何提升服装行业的效率与创新

面料识别技术:AI如何提升服装行业的效率与创新 随着人工智能技术的飞速发展,AI大模型在各个领域都展现出了其强大的应用潜力。特别是在服装行业,AI大模型的图片识别技术正在成为面料识别和设计创新的重要工具。本文将探讨AI大模型在服装行业…

vivado PIN

描述 引脚是基元或层次单元上的逻辑连接点。引脚允许 要抽象掉单元格的内容,并简化逻辑以便于使用。引脚可以 是标量的,包含单个连接,或者可以定义为对多个进行分组的总线引脚 信号在一起。 相关对象 引脚连接到一个单元,并且可以…

羊城杯 2020 a_piece_of_java

考点:JDBC反序列化打CC链动态代理类触发readobject 一眼看过去 好像只有一个mysql-connector-java 可以利用jdbc 可能的攻击路径就有1) Mysql服务器任意文件读取 2) JDBC反序列化打依赖链 出现了一个不常见的依赖库 serialkiller 做了反序列化的过滤器 可以尝试查看其源码 htt…

LabVIEW盾构机状态监测

随着城市化的加速,地铁成为了城市交通的重要组成部分。为了保障地铁施工安全和效率,提出了一种基于LabVIEW的地铁施工盾构异常状态监测方法。该方法利用LabVIEW软件进行数据采集和处理,通过异常监测技术实时监控盾构机的运行状态,…

期末考试老师怎样发成绩

期末成绩的公布,总是让老师感到焦虑。成绩,这一张张的数字,承载着学生一学期的努力,也牵动着家长们的心。 传统的成绩公布方式,写成绩条让学生带回家,或是通过私发家长的方式,都存在一定的弊端。…

如何用多线程执行 unittest 测试用例实现方案

前言 使用python做过自动化测试的小伙伴,想必都知道unittest和pytest这两个单元测试框架,其中unittest是python的官方库,功能相对于pytest来要逊色不少,但是uniitest使用上手简单,也受到的很多的小伙伴喜爱。一直以来都…

数据治理服务解决方案(35页WORD)

方案介绍: 本数据治理服务解决方案旨在为企业提供一站式的数据治理服务,包括数据规划、数据采集、数据存储、数据处理、数据质量保障、数据安全及合规等方面。通过构建完善的数据治理体系,确保企业数据的准确性、完整性和一致性,…

Linux操作系统以及一些操作命令、安装教程

Web课程完结啦,这是Web第一天的课程大家有兴趣可以传送过去学习 http://t.csdnimg.cn/K547r Linux-Day01 课程内容 Linux简介 Linux安装 Linux常用命令 1. 前言 1.1 什么是Linux Linux是一套免费使用和自由传播的操作系统。说到操作系统,大家比…

代码随想录算法训练营第二十六天|39. 组合总和、 40.组合总和II、 131.分割回文串

39. 组合总和 题目链接:39. 组合总和 文档讲解:代码随想录 状态:卡了一会儿 思路:先排序,方便剪枝。允许数字重复使用,因此递归调用时传入当前索引i。 题解: public class Solution {// 用于存…

vivado NODE、PACKAGE_PIN

节点是Xilinx部件上用于路由连接或网络的设备对象。它是一个 WIRE集合,跨越多个瓦片,物理和电气 连接在一起。节点可以连接到单个SITE_, 而是简单地将NETs携带进、携带出或携带穿过站点。节点可以连接到 任何数量的PIP,并且也可以…

Science | 稀土开采威胁马来西亚的生物多样性

马来西亚是一个生物多样性热点地区,拥有超过17万种物种,其中1600多种处于濒临灭绝的风险。马来西亚的热带雨林蕴藏了大部分的生物多样性,并为全球提供重要的生态系统效益,同时为土著社区带来经济和文化价值。同时马来西亚具有可观…

nginx安装环境部署(完整步骤)

在部署nginx前,我们需要进行环境的部署 1.编译工具gcc,g,autoconf,automake ,make sudo apt-get install gcc g autoconf automake make 2.依赖库zlib,openssl,pcre 2.1 openssl下载地址 https://www.open…

韩兴国/姜勇团队在《Trends in Plant Science》发表植物根系氮素再分配的观点文章!

氮素是陆地生态系统中的关键限制性营养元素,通过生物固氮和土壤氮供应通常远低高等植物的氮需求。当土壤氮素供应无法充分满足植物茎叶生长需求时,植物会通过自身营养器官(如根或根茎)再分配来实现氮的内部循环和再利用。尽管植物…

首批50辆苏州金龙纯电大巴交付!武汉通勤客运绿色发展提质升级

随着第一缕阳光跃上黄鹤楼的飞檐,城市逐渐苏醒。在车水马龙中,一辆辆通勤班车穿梭其中,确保通勤保障单位人员的安全出行。而这其中就有武汉市雄翔通勤汽车运输有限公司(以下简称“武汉雄翔”)的身影。 5月底&#xff…

Postman 请求参数传递指南:Query、Path和Body

Postman 作为一个功能强大的工具,极大地简化了 API 测试和调试的过程,提供了发送请求和检查响应的直接方法。本文将着重介绍如何在 Postman 中高效地处理请求参数,以提高 API 测试和开发的便利性。 1、解析请求参数 首先,我们需要…

11.5.k8s中pod的调度-cordon,drain,delete

目录 一、概念 二、使用 1.cordon 停止调度 1.1.停止调度 1.2.解除恢复 2.drain 驱逐节点 2.1.驱逐节点 2.2.参数介绍 2.3.解除恢复 3.delete 删除节点 一、概念 cordon节点,drain驱逐节点,delete 节点,在对k8s集群节点执行维护&am…

深度学习训练——batch_size参数设置过大反而训练更耗时的原因分析

💪 专业从事且热爱图像处理,图像处理专栏更新如下👇: 📝《图像去噪》 📝《超分辨率重建》 📝《语义分割》 📝《风格迁移》 📝《目标检测》 📝《暗光增强》 &a…

重学java 71.网络编程

人生不是坐等暴风雨过去,而是学会在雨中起舞 —— 24.6.14 一、网络编程的基础概念 1.概述: 在网络通信协议下,不同计算机上运行的程序,进行数据传输 比如:通信、视频通话、网络、邮件 只要是计算机之间通过网络进行数据传输,就有…

想上币的项目方怎么去选择交易所

在区块链和加密货币蓬勃发展的今天,许多项目方都渴望通过交易所上线其代币,以扩大影响力、提升流动性和市场认可度。然而,选择合适的交易所并非易事,它关乎项目的未来发展和市场地位。那么,对于有上币意向的项目来说&a…