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

Jetpack Compose中SecureTextField键盘剪贴板掩码显示方案

Jetpack Compose中SecureTextField获焦时隐藏剪贴板明文预览的解决方案

要实现SecureTextField获焦时键盘剪贴板显示掩码、失焦时恢复正常的效果,可通过焦点监听+剪贴板内容临时替换的方式实现,以下是具体步骤和代码示例:

核心思路

通过监听SecureTextField的焦点状态:

  • 获焦时:保存当前剪贴板的真实内容,将剪贴板替换为掩码字符(如"•••••")
  • 失焦时:恢复之前保存的剪贴板真实内容

代码实现

1. 准备状态变量

在Compose函数中定义焦点请求器、剪贴板管理器、保存原剪贴板内容的变量:

val focusRequester = remember { FocusRequester() }
val clipboardManager = LocalClipboardManager.current
var originalClipboardContent by remember { mutableStateOf<ClipboardContent?>(null) }

2. 实现焦点监听与剪贴板控制

给SecureTextField添加焦点监听逻辑,在焦点变化时处理剪贴板:

SecureTextField(
    value = password,
    onValueChange = { password = it },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
    modifier = Modifier
        .focusRequester(focusRequester)
        .onFocusChanged { focusState ->
            if (focusState.isFocused) {
                // 获焦时保存原剪贴板内容,替换为掩码
                originalClipboardContent = clipboardManager.getClipboard()
                clipboardManager.setClipboard(PlainTextClipboardContent("•••••"))
            } else {
                // 失焦时恢复原剪贴板内容
                originalClipboardContent?.let {
                    clipboardManager.setClipboard(it)
                    originalClipboardContent = null
                }
            }
        }
)

3. 完整示例(MainActivity.kt)

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourAppTheme {
                Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background) {
                    Column(
                        modifier = Modifier.padding(16.dp),
                        verticalArrangement = Arrangement.spacedBy(16.dp)
                    ) {
                        var email by remember { mutableStateOf("") }
                        var password by remember { mutableStateOf("") }
                        
                        val focusRequester = remember { FocusRequester() }
                        val clipboardManager = LocalClipboardManager.current
                        var originalClipboardContent by remember { mutableStateOf<ClipboardContent?>(null) }

                        BasicTextField(
                            value = email,
                            onValueChange = { email = it },
                            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Email),
                            modifier = Modifier
                                .fillMaxWidth()
                                .height(56.dp)
                                .border(1.dp, Color.Gray, RoundedCornerShape(4.dp))
                                .padding(horizontal = 16.dp, vertical = 12.dp),
                            decorationBox = { innerTextField ->
                                if (email.isEmpty()) {
                                    Text(text = "Enter email", color = Color.Gray)
                                }
                                innerTextField()
                            }
                        )

                        SecureTextField(
                            value = password,
                            onValueChange = { password = it },
                            keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password),
                            modifier = Modifier
                                .fillMaxWidth()
                                .height(56.dp)
                                .border(1.dp, Color.Gray, RoundedCornerShape(4.dp))
                                .padding(horizontal = 16.dp, vertical = 12.dp)
                                .focusRequester(focusRequester)
                                .onFocusChanged { focusState ->
                                    if (focusState.isFocused) {
                                        originalClipboardContent = clipboardManager.getClipboard()
                                        clipboardManager.setClipboard(PlainTextClipboardContent("•••••"))
                                    } else {
                                        originalClipboardContent?.let {
                                            clipboardManager.setClipboard(it)
                                            originalClipboardContent = null
                                        }
                                    }
                                },
                            decorationBox = { innerTextField ->
                                if (password.isEmpty()) {
                                    Text(text = "Enter password", color = Color.Gray)
                                }
                                innerTextField()
                            }
                        )
                    }
                }
            }
        }
    }
}

注意事项

  • 该方案通过临时替换剪贴板内容实现效果,需确保在失焦时准确恢复原内容,避免丢失用户剪贴板数据
  • 若用户在SecureTextField获焦期间复制新内容,原剪贴板内容会被覆盖,可根据需求添加额外逻辑处理这种场景
  • 部分第三方输入法可能存在自定义剪贴板预览逻辑,该方案可能无法完全兼容所有输入法,建议在主流输入法中测试

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:38:26