You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

限制OutlinedTextField输入为两位数字的自定义键盘问题

问题:自定义键盘下Jetpack Compose数字输入位数限制失效

我使用Jetpack Compose的OutlinedTextField实现用户数字输入功能,要求限制为两位数字。但使用自定义键盘时,正则表达式限制失效,可输入多位数字;启用系统软键盘时,该限制可正常生效。

相关代码如下:

val pattern = Regex("^\d{1,2}$")
OutlinedTextField(
    enabled = false,
    colors = TextFieldDefaults.outlinedTextFieldColors(disabledTextColor = Color.Black, cursorColor = Color.Transparent),
    shape = RectangleShape,
    value = viewModel.text.largestDigit.value,
    onValueChange = { if (it.isEmpty() || it.matches(pattern)) viewModel.text.largestDigit.value = it },
    modifier = Modifier
        .width(IntrinsicSize.Min)
        .padding(horizontal = 1.dp),
    textStyle = TextStyle(fontSize = 25.sp, textAlign = TextAlign.Center),
    label = {
        Text(
            text = "Enter maximum number",
            modifier = Modifier.fillMaxWidth(),
            fontSize = 15.sp,
            textAlign = TextAlign.Center
        )
    }
)

@Composable
fun Keyboard(onKeyPressed: (String) -> Unit) {
    val keys = listOf("1", "2", "3", "4", "5", "6", "7", "8", "9" , "<-", "0", "Enter" )
    LazyVerticalGrid(
        modifier = Modifier
            .fillMaxWidth()
            .padding(bottom = 30.dp)
            .border(BorderStroke(1.dp, Color.Black)),

        columns = GridCells.Fixed(3),
        state = LazyGridState(),
        verticalArrangement = Arrangement.Center,
        horizontalArrangement = Arrangement.Center
    ) {
        items(12) { index ->
            ElevatedCard(
                modifier = Modifier
                    .fillMaxWidth()
                    .wrapContentWidth()
                    .wrapContentHeight()
                    .border(BorderStroke(1.dp, Color.Black))
                    .clickable(
                        onClick = {
                            onKeyPressed(keys[index])
                        },
                    ),
                shape = RectangleShape,
                colors = CardDefaults.elevatedCardColors(containerColor = Color.Green),
                elevation = CardDefaults.cardElevation(),

            ) {
                Text(
                    text = keys[index],
                    modifier = Modifier
                        .fillMaxWidth()
                        .requiredHeight(50.dp),
                    fontSize = 30.sp,
                    fontWeight = FontWeight.Bold,
                    textAlign = TextAlign.Center
                )
            }
        }
    }
}

Keyboard(onKeyPressed = { key ->
    when (key) {
        "<-" -> {viewModel.text.largestDigit.value = viewModel.text.largestDigit.value.dropLast(1)}
        "Enter" -> {
            TODO()
        }
        else -> {viewModel.text.largestDigit.value = viewModel.text.largestDigit.value + key[viewModel.answer.index.value]}
    }
})

问题原因

  • 系统键盘输入会触发OutlinedTextField的onValueChange回调,这里的正则校验逻辑会生效,从而限制输入长度;
  • 自定义键盘是直接修改ViewModel中的largestDigit值,完全绕过了OutlinedTextField的校验逻辑,导致正则限制根本没被执行。

解决思路

方案1:在自定义键盘逻辑中直接添加长度校验

在自定义键盘的按键处理代码里,先判断当前输入长度是否已达2位,再决定是否添加新字符:

Keyboard(onKeyPressed = { key ->
    when (key) {
        "<-" -> {
            viewModel.text.largestDigit.value = viewModel.text.largestDigit.value.dropLast(1)
        }
        "Enter" -> {
            TODO()
        }
        else -> {
            val currentText = viewModel.text.largestDigit.value
            // 限制最多两位数字
            if (currentText.length < 2) {
                // 原代码中key[viewModel.answer.index.value]疑似笔误,自定义键盘的key本身是单个数字字符串,直接拼接即可
                viewModel.text.largestDigit.value = currentText + key
            }
        }
    }
})

方案2:统一校验逻辑到ViewModel层

把输入校验逻辑抽离到ViewModel中,不管是系统键盘还是自定义键盘,都通过ViewModel的方法更新输入值,确保校验逻辑统一:

  1. 在ViewModel中添加校验更新方法:
fun updateLargestDigit(newValue: String) {
    // 注意:Kotlin中反斜杠需要转义,修正正则写法
    val pattern = Regex("^\\d{1,2}$")
    if (newValue.isEmpty() || newValue.matches(pattern)) {
        text.largestDigit.value = newValue
    }
}
  1. 修改OutlinedTextField的onValueChange:
OutlinedTextField(
    // 其他参数保持不变
    onValueChange = { viewModel.updateLargestDigit(it) },
)
  1. 自定义键盘的按键处理也调用该方法:
Keyboard(onKeyPressed = { key ->
    when (key) {
        "<-" -> {
            viewModel.updateLargestDigit(viewModel.text.largestDigit.value.dropLast(1))
        }
        "Enter" -> {
            TODO()
        }
        else -> {
            val currentText = viewModel.text.largestDigit.value
            viewModel.updateLargestDigit(currentText + key)
        }
    }
})

方案3:修正正则表达式(可选)

原正则Regex("^\d{1,2}$")在Kotlin中需要转义反斜杠,正确写法应为Regex("^\\d{1,2}$"),虽然系统键盘下能生效,但修正后可避免潜在的正则匹配问题。

内容的提问来源于stack exchange,提问作者JD74

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 22:28:35