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 核心实现流程
- 声明状态:
var password by remember { mutableStateOf("") } - 绑定输入框:设置
value = password、onValueChange = { password = it } - 应用转换:
visualTransformation = PasswordVisualTransformation() - 处理焦点与错误:配合
isError、errorMessage等参数增强安全性提示
仅使用
visualTransformation 并不能加密或保护内存中的密码。它只改变屏幕显示。实际密码值仍以明文形式存储在 password 状态中。3.4 状态与转换的关系示意图
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 缓存转换结果。