Android自定义TextInputEditText问题:光标始终停留在起始位置
解决自定义密码输入框光标跳回起始位置的问题
嘿,这个问题我太熟了!自定义TextInputEditText做密码输入框时,要是直接在文本变化回调里替换内容,大概率会碰到光标每次都跳回开头的坑。先给你捋捋原因,再上解决方案:
为啥光标会乱跑?
核心原因是:当你调用setText()更新输入框内容时,Android系统默认会把光标重置到文本的起始位置。而且如果没做特殊处理,还会触发TextWatcher的无限循环回调,雪上加霜。
一步步解决问题
1. 加个标记位避免循环更新
首先得区分开「用户手动输入」和「代码内部更新文本」,不然每次setText()都会触发文本变化监听,陷入死循环。
2. 先存光标位置再恢复
在更新文本前,先把当前光标所在的位置记下来,等文本替换完成后,再把光标挪回原来的位置(如果位置超出新文本长度,就放末尾)。
修正后的完整代码
public class CustomInputEditTextWithSecret extends TextInputEditText { private final String SECRET_MASK = "●●●●●●"; // 换成你要显示的秘密字符串,比如你的"123456" private boolean isUpdating = false; // 标记是否是内部更新,防止循环 private String realPassword = ""; // 存用户真实输入的密码,因为显示的是掩码 public CustomInputEditTextWithSecret(Context context) { super(context); init(); } public CustomInputEditTextWithSecret(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CustomInputEditTextWithSecret(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { // 保持密码输入的系统特性 setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {} @Override public void onTextChanged(CharSequence s, int start, int before, int count) { // 如果是内部更新文本,直接跳过,避免循环 if (isUpdating) return; isUpdating = true; // 先保存当前光标位置 int cursorPos = getSelectionStart(); // 记录用户真实输入的内容(这里根据你的需求调整,比如追加新输入的字符) if (count > 0) { realPassword += s.subSequence(start, start + count).toString(); } else if (before > 0) { // 处理删除操作 if (cursorPos < realPassword.length()) { realPassword = realPassword.substring(0, cursorPos) + realPassword.substring(cursorPos + before); } else { realPassword = realPassword.substring(0, realPassword.length() - before); } } // 设置显示的掩码文本 setText(SECRET_MASK); // 恢复光标位置,不能超过掩码长度 setSelection(Math.min(cursorPos, SECRET_MASK.length())); isUpdating = false; } @Override public void afterTextChanged(Editable s) {} }); } // 对外提供获取真实密码的方法 public String getRealPassword() { return realPassword; } }
几个关键细节
isUpdating标记位:这是避免无限循环的关键,不然每次setText()都会触发onTextChanged,一直重复更新。- 真实密码单独存储:因为输入框显示的是掩码(比如你的"123456"),所以必须用单独变量存用户实际输入的内容,不然拿不到真实密码。
- 光标位置处理:恢复光标时要判断是否超出掩码长度,不然会报错,直接设到末尾就好。
额外小建议
如果你的需求只是显示密码掩码,其实不用自定义View,直接用系统的TextInputEditText,设置inputType="textPassword",系统会自动显示圆点掩码,还不会有光标问题。只有当你需要自定义掩码内容(比如固定显示"123456")时,才需要上面的自定义方案。
内容的提问来源于stack exchange,提问作者j2emanue
相关产品推荐
相关产品推荐

