【问题标题】:Android Jetpack Compose: Keyboard changing from numeric to alphabets after modifying input textAndroid Jetpack Compose:修改输入文本后键盘从数字变为字母
【发布时间】:2022-01-20 20:55:55
【问题描述】:

在 Jetpack Compose 中探索 TextField 时,我遇到了一个案例,我必须修改在字段中键入的输入。 例如输入3个字符后加逗号

这就是我的做法。

@Composable
fun TFDemo() {
    var fieldValue by remember { mutableStateOf(TextFieldValue("")) }

    TextField(
        value = fieldValue,
        onValueChange = {
            val newMessage = it.text.let { text -> if (text.length == 3) "$text," else text }
            fieldValue = it.copy(newMessage, selection = TextRange(newMessage.length))
        },
        keyboardOptions = KeyboardOptions(autoCorrect = false),
    )
}

但是在运行之后,我意识到添加逗号后,键盘视图从数字/符号变回了字母,这不应该是这种情况。 为了清楚起见,请参阅下面的视频输出

正如您在下面的视频中看到的,当我输入“111”时,附加了逗号,突然键盘的数字视图再次变为字母。


这里我修改了TextFieldValueselection,这样无论何时添加逗号,光标始终位于消息的末尾。

【问题讨论】:

  • 看起来像一个错误,我建议你report它来撰写问题跟踪器。作为 tmp 解决方案,现在考虑使用visualTransformation

标签: android android-layout user-interface textfield android-jetpack-compose


【解决方案1】:

这种情况正是VisualTransformation 的用途。

这是一位 Google 员工对 another issue 的评论:

我认为我们不能轻易解决这个问题。

onValueChanged 回调中的过滤文本一般不推荐,因为文本状态与进程外输入法(软键盘)共享。过滤文本是指文本内容在内部发生变化,然后将新的状态通知给 IME。这不是通向 IME 的正常路径,不同的 IME 对这种意外状态变化的反应不同。一些 IME 可能会尝试重构构图,另一些可能会放弃并开始新会话等。这主要是由于历史原因,从现在开始很难修复。因此,请避免在 onValueChanged 回调中过滤文本并考虑以下替代方案:

  1. (推荐)不要过滤它并显示错误消息。 (此处无关)
  2. 使用 VisualTransformation 在不修改编辑缓冲区的情况下更改视觉输出。

【讨论】:

  • 谢谢,成功了!
【解决方案2】:

根据上面提到的答案,VisualTransformation 是这种情况的完美解决方案,我们不应该直接修改 TextField 的缓冲区。因为VisualTransformation 只是改变了文本的视觉输出,而不是实际的文本。

I've written an article on this scenario here 我已经详细解释了这一点。

解决方案:

@Composable
fun TextFieldDemo() {
    var message by remember { mutableStateOf("") }

    TextField(
        value = message,
        placeholder = { Text("Enter amount or message") },
        onValueChange = { message = it },
        visualTransformation = AmountOrMessageVisualTransformation()
    )
}

class AmountOrMessageVisualTransformation : VisualTransformation {
    override fun filter(text: AnnotatedString): TransformedText {

        val originalText = text.text
        val formattedText = formatAmountOrMessage(text.text)

        val offsetMapping = object : OffsetMapping {

            override fun originalToTransformed(offset: Int): Int {
                if (originalText.isValidFormattableAmount) {
                    val commas = formattedText.count { it == ',' }
                    return when {
                        offset <= 1 -> offset
                        offset <= 3 -> if (commas >= 1) offset + 1 else offset
                        offset <= 5 -> if (commas == 2) offset + 2 else offset + 1
                        else -> 8
                    }
                }
                return offset
            }

            override fun transformedToOriginal(offset: Int): Int {
                if (originalText.isValidFormattableAmount) {
                    val commas = formattedText.count { it == ',' }
                    return when (offset) {
                        8, 7 -> offset - 2
                        6 -> if (commas == 1) 5 else 4
                        5 -> if (commas == 1) 4 else if (commas == 2) 3 else offset
                        4, 3 -> if (commas >= 1) offset - 1 else offset
                        2 -> if (commas == 2) 1 else offset
                        else -> offset
                    }
                }
                return offset
            }
        }

        return TransformedText(
            text = AnnotatedString(formattedText),
            offsetMapping = offsetMapping
        )
    }
}

【讨论】:

    猜你喜欢
    • 2022-01-07
    • 2021-05-06
    • 1970-01-01
    • 1970-01-01
    • 2021-10-31
    • 2021-04-10
    • 1970-01-01
    • 1970-01-01
    • 2012-10-26
    相关资源
    最近更新 更多