用TextWatcher限制输入长度并弹出提示

来源:互联网 发布:数据库笔试题及答案 编辑:程序博客网 时间:2024/06/06 13:19

在EditText里面输入,限制输入长度并弹出提示,原本,这是最初级和普遍的需求了,但在细微处却有点小不方便。
 
方法之一,是在xml中添加限制:maxLength="10"。但是,当用户输入达到或超过限制时没有提示。方法之二,给EditText添加TextWatcher监控,在输入超过限制时给予提示,并恢复为之前的状态。试了一下,没法把方法一和方法二结合起来,用maxLength限制后,超过限制时,只是不能输入了,但触发不了TextWatcher,找不到机会触发弹框提示。


给予超出限制的提示很容易,但怎么恢复为本次输入之前状态却需要小心。注意点包括,用户可能键入单个字符,也可能拷贝一个字符串进去,输入光标不一定在字符串尾巴处,也可能在中间或开头。此外,用户可能已经标记高亮了部分字符串。无论哪种,只要输入后会超过限制,那么我们都要恢复成输入之前的状态。
 
使用TextWatcher做输入恢复的步骤是,在TextWatcher的beforeTextChanged方法中保存本次输入之前的字符串及光标位置,接着在afterTextChanged方法中对输入后的字符串长度做检查,如果超过限制,那么在这一步恢复之前的字符串及光标位置。


Android的问题在于,TextWatcher接口中afterTextChanged方法的内部设计比较不友好,存在一个递归嵌套。也即,TextWatcher的正常流程是“beforeTextChanged-->onTextChanged-->afterTextChanged”,但是,当我们在afterTextChanged方法中设法恢复或说修改字符串时,在afterTextChanged方法还没返回的情况下,流程又被触发进入新一个“beforeTextChanged-->onTextChanged-->afterTextChanged”流程,这是因为TextWatcher的设定是,如果字符串被修改,不论在哪,包括我们在第三步afterTextChanged里面修改字符串,都会立即触发并进入新一轮的“beforeTextChanged-->onTextChanged-->afterTextChanged”流程,稍不注意,这里就递归不已,马上耗完内存并stackoverflow了。
 
如下是限制输入长度,并弹出toast的代码,设法避免了嵌套递归:

public class LimitTextWatcher implements TextWatcher {    public interface IF_callback{        void callback(int left);    }    public IF_callback if_callback;    EditText editText;    int maxLength;    int cursorPositionLast;    String textLast;    boolean bypass;    public LimitTextWatcher(EditText editText, int maxLength, IF_callback if_callback) {        this.editText = editText;        this.maxLength = maxLength;        this.if_callback = if_callback;    }    @Override    public void beforeTextChanged(CharSequence s, int start, int count, int after) {        if (bypass) {            bypass = false;        } else {            StringBuilder stringBuilder = new StringBuilder();            stringBuilder.append(s);            textLast = stringBuilder.toString();            this.cursorPositionLast = editText.getSelectionStart();        }    }    @Override    public void onTextChanged(CharSequence s, int start, int before, int count) {    }    @Override    public void afterTextChanged(Editable s) {        if (s.toString().length() > maxLength) {            int left = maxLength - s.toString().length();            bypass = true;            s.clear();            bypass = true;            s.append(textLast);            editText.setSelection(this.cursorPositionLast);            if (if_callback != null) {                if_callback.callback(left);            }        }    }}edit_text.addTextChangedListener(new LimitTextWatcher(edit_text, MAX_LENGTH, new LimitTextWatcher.IF_callback() {        @Override        public void callback(int left) {            if(left <= 0) {                Toast.makeText(MainActivity.this, "input is full", Toast.LENGTH_SHORT).show();            }        }    }));

如上代码有个小缺陷:如果在输入之前,用户已经标记高亮了一段子字符串,那么无法恢复这段高亮。android提供设置高亮的头尾光标的方法不起作用,不知为何。

以上的完整代码:https://github.com/maxyou/Limit-EditText



阅读全文
0 0
原创粉丝点击