Compose信用卡格式输入框填充满后删除异常问题求助
问题原因及修复方案
核心问题:输入内容长度判断逻辑错误
你在onValueChange里的判断条件是原文本长度<=16时才更新内容,这会导致当原文本已经是16位时,用户输入新字符会让it的长度变成17,此时原文本长度16满足<=16的条件,text会被赋值为17位的字符串。而你的VisualTransformation和OffsetMapping都是基于16位原文本设计的,超长的原文本会导致光标偏移映射混乱,最终引发删除操作异常。
修复步骤
1. 修正onValueChange的长度限制逻辑
把判断条件从原文本长度改为新输入内容的长度不超过16,确保存储的text始终最多16位:
onValueChange = { newText -> if (newText.length <= 16) { text = newText } }
2. 优化VisualTransformation的冗余处理(可选)
因为已经通过onValueChange限制了text长度不超过16,所以filter方法里的截断逻辑可以简化,避免重复处理:
visualTransformation = object : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText { var out = "" for (i in text.text.indices) { out += text.text[i] if (i % 4 == 3 && i != 15) out += "-" } return TransformedText( AnnotatedString(out), creditCardOffsetMapping ) } }
3. 验证OffsetMapping逻辑
你的creditCardOffsetMapping逻辑是正确的,16位原文本转换后是19位(包含3个分隔符),偏移映射的计算没问题,修复长度限制后即可正常工作。
修复后的完整代码示例
// XXXX-XXXX-XXXX-XXXX var text by remember { mutableStateOf("") } OutlinedTextField( value = text, onValueChange = { newText -> if (newText.length <= 16) { text = newText } }, visualTransformation = object : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText { var out = "" for (i in text.text.indices) { out += text.text[i] if (i % 4 == 3 && i != 15) out += "-" } return TransformedText( AnnotatedString(out), creditCardOffsetMapping ) } } ) // Making XXXX-XXXX-XXXX-XXXX string. val creditCardOffsetMapping = object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { if (offset <= 3) return offset if (offset <= 7) return offset + 1 if (offset <= 11) return offset + 2 if (offset <= 16) return offset + 3 return 19 } override fun transformedToOriginal(offset: Int): Int { if (offset <= 4) return offset if (offset <= 9) return offset - 1 if (offset <= 14) return offset - 2 if (offset <= 19) return offset - 3 return 16 } }
内容的提问来源于stack exchange,提问作者fergdev
相关产品推荐
相关产品推荐

