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

Jetpack Compose美国手机号VisualTransformation光标问题及功能需求

美国手机号实时格式化(Jetpack Compose)

问题场景

需要实现Jetpack Compose输入框的美国手机号实时格式化,规则如下:

  • 空输入时显示+1
  • 输入过程自动排版,最终格式为+1 (123) 456-7890
  • 当前已实现基础格式化,但存在两个问题:空输入时光标位置错误;无法在字符中间插入数字

修复后的完整实现

1. 手机号格式化VisualTransformation

private val phoneNumberFilter = VisualTransformation { text ->
    val rawDigits = text.text.takeWhile { it.isDigit() }.take(10)
    val formatted = buildString {
        append("+1 ")
        if (rawDigits.isNotEmpty()) {
            append("(")
            append(rawDigits.take(3))
            if (rawDigits.length > 3) {
                append(") ")
                append(rawDigits.substring(3, 6))
                if (rawDigits.length > 6) {
                    append("-")
                    append(rawDigits.substring(6))
                }
            }
        }
    }

    val mapping = object : OffsetMapping {
        override fun originalToTransformed(offset: Int): Int {
            return when (offset) {
                0 -> 3 // 空输入或光标在最前时,定位到+1后面的空格后
                in 1..3 -> offset + 3 // 前3位数字对应格式化后的位置:+1 (X...
                in 4..6 -> offset + 4 // 中间3位对应:+1 (XXX) X...
                else -> offset + 5 // 最后4位对应:+1 (XXX) XXX-...
            }
        }

        override fun transformedToOriginal(offset: Int): Int {
            return when (offset) {
                in 0..3 -> 0 // 点击+1区域,光标回到原始最前
                in 4..6 -> offset - 3 // 对应前3位原始位置
                in 7..9 -> offset - 4 // 对应中间3位原始位置
                else -> offset - 5 // 对应最后4位原始位置
            }.coerceIn(0, rawDigits.length)
        }
    }

    TransformedText(AnnotatedString(formatted), mapping)
}

2. 输入框UI代码

var phone by remember { mutableStateOf("") }

OutlinedTextField(
    modifier = Modifier.fillMaxWidth(),
    value = phone,
    onValueChange = { input ->
        val digits = input.takeWhile { it.isDigit() }.take(10)
        phone = digits
    },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Phone),
    visualTransformation = phoneNumberFilter,
    placeholder = { Text(text = "+1") }
)

修复关键点说明

  • 空输入光标修正:在originalToTransformed中,当原始偏移为0时直接返回3(对应+1 之后的位置),解决空输入时光标错位问题;transformedToOriginal处理点击+1区域时,将光标定位到原始输入最前端。
  • 中间插入支持:通过分段偏移映射,确保光标在格式化后的任意位置点击时,都能正确映射到原始数字的对应位置,支持在任意位置插入或删除数字。
  • 格式化逻辑优化:使用buildString高效构建格式化文本,按分段处理不同长度的输入,确保逐步排版符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 18:05:29