0

我有一个表单,用户可以在EditText字段中输入一些数据。其中一个EditText小部件用于电子邮件地址。我使用的是TextWatcher以确保文本始终是小写如下:Android - 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());并使用if转义递归循环,我可以控制插入位置到EditText的末尾,但我无法找到一种方法将我的插入符号保留在特定位置。例如,如果我写了“myema(il missing)@ something.com”,并且想要返回来对每个字母进行修改,那么在字符串结尾处插入脱字符号。

现在是奇怪的部分。在beforeTextChanged(...)onTextChanged(...)之前插入的插入符的位置在我键入内容时,插入符的位置在每种情况下都被适当地改变了,但是,当我们输入递归调用时插入符的位置被报告为0。当我实际键入时,插入符号运动也被注册,但是因为在递归调用中没有插入符号的移动,而不是在EditText中“粘贴”文本,所以我没有找到位置变化。我保持脱字符的位置?我曾经是实际将字符串分文本。将所有内容都写入插入符号中,使其更改将其与txtEmail.setSelection(temp.length());一起扔到那里,然后在其他步骤中添加字符串的其余部分(尚未尝试过)。是否有任何其他(更简单/更高效)的方式可以通过内置工具处理?

在此先感谢!

+0

你为什么把它反正结束了? – creativecreatorormaybenot

回答

1

也许你已经走近了这艰难的路。为什么不使用

android:digits="qwertyuiopasdfghjklzxcvbnm_,[email protected]," 

EditText for email?如果您允许用户输入任何其他字符,只需将其添加到android:digits字段。

编辑由OP:

以下亚历山的意见后(见注释)注销并重新注册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(); 
      } 
     } 
    }); 
+0

这种方法最大的问题是,如果我输入大写字母,则字符根本不会注册。另外我需要基本上把整个键盘放在'android:digits =“...”'中,根据[电子邮件地址的形式定义]覆盖所有可能的组合(https://en.wikipedia.org/wiki/Email_address#Syntax )。 我搜索了很长时间,很难找到我想要的功能,我认为这是实现它的唯一方法。我很想被证明是错误的,但是;) – MadDim

+0

啊哈,所以如果用户输入大写'A',你必须显示小写字母'a'?为了避免设置光标手动,在使用'txtEmail.setText(temp)'设置文本之前只注销TextWatcher,然后再注册它是否有帮助?我猜,这样你可以优雅地避免递归调用。 –

+0

Aaaand你摇滚......从来没有想过试图取消注册TextWatcher。它实际上看起来很奇怪,当我读到你的评论时,在里面取消注册!显然,Java/Android并不在意(这个''真是神奇有时!)和它的作品!如果您不介意,我将编辑您的答案,并对所做的更改进行标记。 – MadDim