【问题标题】:Android - EditText TextWatcher to keep lowercase, cannot keep caret (input cursor) positionAndroid - EditText TextWatcher 保持小写,不能保持插入符号(输入光标)位置
【发布时间】:2017-04-20 10:56:54
【问题描述】:

我有一个表单,用户可以在其中在 EditText 字段中输入一些数据。其中一个 EditText 小部件用于电子邮件地址。我正在使用 TextWatcher 来确保文本始终为小写,如下所示:

txtEmail.addTextChangedListener(new TextWatcher()
    {
        String prevString = "";
        boolean delAction = false;

        @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 (s.length() < prevString.length())
                delAction = true;
            else
                delAction = false;
        }

        @Override
        public void afterTextChanged(Editable s)
        {
            if (!delAction)
            {
                String temp = s.toString().toLowerCase();
                if (!temp.equals(prevString))
                {
                    prevString = temp;
                    txtEmail.setText(temp); // Recursive
                    txtEmail.setSelection(temp.length());
                }
            }
            else
            {
                prevString = s.toString();
            }
        }
    });

onTextChanged(...)我也在做一个比较,以确保删除工作正常。

现在解决问题。 txtEmail.setText(temp); 导致整个 Watcher 递归运行。我可以通过添加 txtEmail.setSelection(temp.length()); 来控制插入符号的位置以转到 EditText 的末尾,并使用 if 转义递归循环,但我找不到将插入符号保持在特定点的方法。例如,如果我写了“myema(il missing)@something.com 并想在输入的每个字母处返回以进行更正,则插入符号位于字符串的末尾。

现在是奇怪的部分。我尝试将插入符号的位置保持在beforeTextChanged(...)onTextChanged(...) 之前。在我输入某些内容的那一刻,插入符号的位置在每种情况下都会正确更改。但是,当我们进入递归调用时,插入符号的位置报告为 0。我猜当我实际键入时,插入符号的移动也被注册了,但是因为在递归调用中没有插入符号移动而不是“粘贴” " EditText 中的文本我没有得到位置变化。

因此问题是:我怎样才能保持插入符号的位置?我的想法是实际上对文本进行子串化。将所有内容都放到插入符号中,使更改与txtEmail.setSelection(temp.length()); 一起扔到那里,然后在 else 步骤中附加字符串的其余部分(目前尚未尝试)。有没有其他(更简单/高效)的方法可以使用内置工具来处理?

提前致谢!

【问题讨论】:

  • 为什么要放到最后呢?

标签: android recursion android-edittext caret android-textwatcher


【解决方案1】:

也许您已经以艰难的方式解决了这个问题。为什么不使用

android:digits="qwertyuiopasdfghjklzxcvbnm_,.@.," 

对于电子邮件的 EditText?如果您允许用户输入任何其他字符,只需将它们添加到 android:digits 字段。

由 OP 编辑​​:

在按照 Alexandru 的建议(参见 cmets)取消注册并再次注册 TextWatcher 后,代码发生了更改并按如下方式工作:

    txtEmail.addTextChangedListener(new TextWatcher()
    {
        String prevString = "";
        boolean delAction = false;
        int caretPos = 0;

        @Override
        public void beforeTextChanged(CharSequence s, int start, int count, int after)
        {
            caretPos = txtEmail.getSelectionStart();
        }

        @Override
        public void onTextChanged(CharSequence s, int start, int before, int count)
        {
            if (s.length() < prevString.length())
                delAction = true;
            else
                delAction = false;
        }

        @Override
        public void afterTextChanged(Editable s)
        {
            if (!delAction)
            {
                prevString = s.toString().toLowerCase();
                txtEmail.removeTextChangedListener(this);
                txtEmail.setText(prevString);
                txtEmail.addTextChangedListener(this);
                txtEmail.setSelection(caretPos + 1);
            }
            else
            {
                txtEmail.setSelection(caretPos - 1);
                prevString = s.toString();
            }
        }
    });

【讨论】:

  • 这种方法最大的问题是,如果我输入大写字母,那么字符根本不会注册。另外,我基本上需要将整个键盘放在android:digits="..." 中,以根据email address formal definitions 覆盖所有可能的组合。我长期努力地寻找我想要的那种功能,我认为这是实现它的唯一方法。不过我很想被证明是错误的;)
  • 啊哈,所以如果用户输入大写'A',你必须显示小写'a'?为了避免手动设置光标,在使用txtEmail.setText(temp)设置文本之前取消注册TextWatcher然后再次注册它会不会有帮助?我猜这样你就可以优雅地避免递归调用。
  • Aaaand you rock... 从没想过要注销 TextWatcher。当我读到你的评论时,它实际上看起来很奇怪,在里面取消注册!显然 Java/Android 不在乎(this 有时真的很神奇!!!)而且它有效!!!如果您不介意,我将使用我所做的更改来编辑您的答案,并标记它。
  • 当然,很高兴它有帮助。其实一点也不奇怪。您可以查看 TextView 的 source code,它是 EditText 的父类。您可以看到 TextWatcher 是一个普通的监听器,没有什么比这更高级的了。不熟悉here the listener(observer)模式可以查看。
猜你喜欢
  • 2012-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-11
  • 2010-10-15
  • 1970-01-01
  • 2015-11-13
  • 1970-01-01
相关资源
最近更新 更多