BasicTextField密码输入框改造需求:实现内容挤压式输入
实现BasicTextField密码输入超出可视长度时挤出前方字符的效果
要实现输入内容超出可视宽度时,新字符在末尾添加、前方旧字符被挤出视野的效果,可通过两种方案实现,以下是具体说明和代码修改:
方案一:通过滚动控制始终显示末尾字符
核心思路是让TextField的水平滚动始终定位到文本最右侧,确保最新输入的字符始终处于可视区域内,实际密码值保持完整。
修改后的完整代码
@Composable fun PasswordInputField( password: String, passwordMaxCharacterCount: Int, passwordOnValueChange: (String) -> Unit, hint: String, checkStatus: Boolean, checkEvent: (Boolean) -> Unit, authText: AuthTextStyle, AuthEditTextColor: Color ) { val isFocused = remember { mutableStateOf(false) } val scrollState = rememberScrollState() // 密码内容变化时自动滚动到最右侧 LaunchedEffect(password) { scrollState.scrollTo(scrollState.maxValue) } BasicTextField( value = password, onValueChange = { if (it.length <= passwordMaxCharacterCount) { password = it passwordOnValueChange(it) } }, modifier = Modifier .height(50.dp) .fillMaxWidth() .padding(start = 30.dp, end = 30.dp) .onFocusChanged { isFocused.value = it.isFocused } .background(AuthEditTextColor, shape = RoundedCornerShape(size = 13.dp)), visualTransformation = if (checkStatus) VisualTransformation.None else PasswordVisualTransformation(), textStyle = authText.bodyMedium, maxLines = 1, keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password), decorationBox = { innerTextField -> Row( modifier = Modifier .padding(start = 20.dp, end = 30.dp), verticalAlignment = Alignment.CenterVertically ) { if (password.isEmpty() && !isFocused.value) Text(text = hint, style = authText.bodySmall) // 给输入区域添加水平滚动绑定 Box(modifier = Modifier .width(100.dp) .horizontalScroll(scrollState)) { innerTextField() } Spacer(modifier = Modifier.weight(1f)) PasswordStatusCheckBox(checkStatus) { checkEvent(it) } } } ) }
关键修改点
- 添加
rememberScrollState()创建滚动状态,绑定到输入区域的horizontalScroll修饰符,开启水平滚动。 - 通过
LaunchedEffect(password)监听内容变化,每次更新后自动滚动到文本最末端,确保新输入字符始终可见。 - 实际密码值保持完整,仅通过滚动控制可视范围,不影响业务逻辑。
方案二:自定义视觉转换固定显示末尾字符
如果需要精准控制显示的字符数量(比如固定显示最后6个),可通过自定义VisualTransformation直接截断文本,更贴合"前方字符被挤出"的直观效果。
自定义视觉转换类
class FixedLengthVisualTransformation(private val showLength: Int) : VisualTransformation { override fun filter(text: AnnotatedString): TransformedText { // 只保留末尾指定数量的字符 val displayedText = if (text.length <= showLength) { text } else { AnnotatedString(text.takeLast(showLength)) } // 处理光标位置映射,确保光标始终在末尾 return TransformedText( displayedText, object : OffsetMapping { override fun originalToTransformed(offset: Int): Int { return offset.coerceAtLeast(text.length - showLength) - (text.length - showLength) } override fun transformedToOriginal(offset: Int): Int { return offset + (text.length - showLength).coerceAtLeast(0) } } ) } }
使用方式
替换原代码中的visualTransformation:
visualTransformation = if (checkStatus) VisualTransformation.None else FixedLengthVisualTransformation(6), // 固定显示最后6个字符
这种方式无需依赖滚动逻辑,直接截断显示指定长度的末尾字符,更符合"挤出前方字符"的需求。
内容的提问来源于stack exchange,提问作者HamTory
相关产品推荐
相关产品推荐

