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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 23:25:29