3. 核心概念:输入框状态管理与 visualTransformation

安全密码输入框的核心价值在于即时状态感知与视觉隐私保护。Compose 通过状态管理控制文本内容,通过 visualTransformation 控制显示效果。本章逐层拆解这两个概念,并给出完整的实现流程。

3.1 输入框状态管理

在 Jetpack Compose 中,TextField 是受控组件,其显示内容由外部状态驱动。常用的状态管理方式:

  • remember { mutableStateOf("") } —— 保存输入文本,组合函数重组时保持状态。
  • by delegates —— 使用 by remember { mutableStateOf() } 简化属性访问。
  • derivedStateOf —— 当需要根据输入值计算派生状态(如密码强度)时使用。
状态变量必须声明在 Composable 函数内,并通过 value 属性或 by 代理读写。输入框通过 value 和 onValueChange 参数双向绑定。
@Composable
fun PasswordField() {
    var password by remember { mutableStateOf("") }
    TextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("密码") },
        singleLine = true
    )
}

3.2 visualTransformation 与 passwordVisualTransformation

visualTransformation 是一个接口,定义如何将输入的原始文本转换为显示文本。两个核心方法:

方法作用典型用途
filter(AnnotatedString)返回转换后的 TransformedText遮罩、格式化(手机号、银行卡号)
initialCursorOffset光标偏移量调整避免光标出现在遮罩字符前

passwordVisualTransformation() 是官方提供的标准实现,将所有可见字符替换为圆点(·),并隐藏最后输入的字符(可选掩码字符)。

TextField(
    value = password,
    onValueChange = { password = it },
    visualTransformation = PasswordVisualTransformation(),
    label = { Text("密码") }
)
若需自定义掩码字符(例如使用 “*”),可调用 PasswordVisualTransformation(mask = '*')。

3.3 核心实现流程

  1. 声明状态:var password by remember { mutableStateOf("") }
  2. 绑定输入框:设置 value = password、onValueChange = { password = it }
  3. 应用转换:visualTransformation = PasswordVisualTransformation()
  4. 处理焦点与错误:配合 isError、errorMessage 等参数增强安全性提示
仅使用 visualTransformation 并不能加密或保护内存中的密码。它只改变屏幕显示。实际密码值仍以明文形式存储在 password 状态中。

3.4 状态与转换的关系示意图

输入框状态与 visualTransformation 流程 用户输入 状态管理
mutableStateOf visualTransformation 显示文本
圆点或自定义
真实密码(内存) 可被读取 转换规则 状态更新 💡 visualTransformation 只改变视觉呈现,不改变输入框内部存储的 value。 密码安全还需额外的加密与传输保护措施。

3.5 调试与验证

  • 打印状态值:在 onValueChange 中 Log.d("Pwd", password),确认内容未丢失。
  • 焦点丢失测试:切换 App 到后台再返回,检查输入框是否保留内容。
  • 无障碍测试:开启 TalkBack,确认密码框读出的内容为“密码,已编辑”而非明文。

3.6 常见错误与优化

错误原因解决方案
输入框不显示内容(完全空白)未设置 visualTransformation 且 TextField 默认不遮盖检查是否误用了 inputType?在 Compose 中直接设置 visualTransformation
光标定位异常自定义 visualTransformation 未正确处理 offsetMapping使用 OffsetMapping.Identity 或基于快捷键映射
输入框重组时闪烁状态提升到不稳定的作用域将 remember 移至 Composable 内部或 ViewModel 中使用 stateIn
密码可见性切换后状态丢失使用了两个独立的 TextField用一个 visualTransformation 变量控制即可,无需重建输入框
性能优化:避免在 visualTransformation 中执行耗时计算(如正则复杂匹配)。如果必须自定义,使用 derivedStateOf 缓存转换结果。

3.7 本章小结