Jetpack Compose中如何实现带冒号的时间输入键盘?
在Jetpack Compose中实现带冒号的时间输入TextField的几种方式
方法1:自定义VisualTransformation + 输入逻辑处理
通过自定义VisualTransformation自动插入冒号,同时在onValueChange里控制输入合法性(仅允许数字、限制长度、处理冒号的插入与删除),确保输入始终符合HH:mm格式。
示例代码:
@Composable fun TimeInputTextField( value: String, onValueChange: (String) -> Unit, modifier: Modifier = Modifier ) { TextField( value = value, onValueChange = { newText -> // 过滤所有非数字字符 val filteredDigits = newText.filter { it.isDigit() } // 根据输入长度格式化文本 val formattedTime = when (filteredDigits.length) { 1 -> filteredDigits 2 -> "$filteredDigits:" in 3..4 -> "${filteredDigits.substring(0,2)}:${filteredDigits.substring(2)}" else -> filteredDigits.take(4).let { "${it.substring(0,2)}:${it.substring(2)}" } } onValueChange(formattedTime) }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), visualTransformation = VisualTransformation { text -> val rawDigits = text.text.filter { it.isDigit() } val displayText = when (rawDigits.length) { 1 -> rawDigits 2 -> "$rawDigits:" in 3..4 -> "${rawDigits.substring(0,2)}:${rawDigits.substring(2)}" else -> rawDigits.take(4).let { "${it.substring(0,2)}:${it.substring(2)}" } } TransformedText(AnnotatedString(displayText), OffsetMapping.Identity) }, singleLine = true, maxLines = 1, modifier = modifier ) }
方法2:自定义InputFilter控制格式
通过InputFilter直接拦截输入,限制长度、过滤非数字并自动插入冒号,无需在onValueChange里重复处理逻辑。
示例代码:
class TimeInputFilter : InputFilter { override fun filter( source: CharSequence?, start: Int, end: Int, dest: Spanned?, dstart: Int, dend: Int ): CharSequence? { val newInput = (dest?.toString() ?: "").replaceRange(dstart, dend, source ?: "") val digitsOnly = newInput.filter { it.isDigit() } val formatted = when (digitsOnly.length) { 1 -> digitsOnly 2 -> "$digitsOnly:" in 3..4 -> "${digitsOnly.substring(0,2)}:${digitsOnly.substring(2)}" else -> digitsOnly.take(4).let { "${it.substring(0,2)}:${it.substring(2)}" } } return if (formatted != newInput) formatted else null } } @Composable fun TimeInputWithFilter() { var time by remember { mutableStateOf("") } TextField( value = time, onValueChange = { time = it }, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number), singleLine = true, maxLines = 1, filters = arrayOf(TimeInputFilter()) ) }
方法3:结合TimePicker弹窗(替代手动输入)
如果允许用户通过弹窗选择时间而非手动输入,用Compose自带的TimePickerDialog更省心,还能避免输入非法值:
示例代码:
@Composable fun TimePickerTextField() { var time by remember { mutableStateOf("") } var showPicker by remember { mutableStateOf(false) } TextField( value = time, onValueChange = {}, // 禁用手动输入 enabled = false, trailingIcon = { IconButton(onClick = { showPicker = true }) { Icon(Icons.Default.Schedule, contentDescription = "选择时间") } } ) if (showPicker) { val initialTime = LocalTime.now() var selectedTime by remember { mutableStateOf(initialTime) } TimePickerDialog( onDismissRequest = { showPicker = false }, confirmButton = { TextButton(onClick = { time = "${selectedTime.hour.toString().padStart(2, '0')}:${selectedTime.minute.toString().padStart(2, '0')}" showPicker = false }) { Text("确认") } }, dismissButton = { TextButton(onClick = { showPicker = false }) { Text("取消") } }, timePicker = { TimePicker(state = rememberTimePickerState( initialHour = initialTime.hour, initialMinute = initialTime.minute ).apply { selectedTime = LocalTime.of(hour, minute) }) } ) } }
内容的提问来源于stack exchange,提问作者Dmitrij Kiltau
相关产品推荐
相关产品推荐

