扩展TextWatcher实现监听EditText字数

在Android开发中,有时会需要监听某个EditText中已输入的字数,达到要求后触发某个行为,例如账号或者密码输入框限定最少输入6位英文或数字,达到6位后登录按钮才变为可用。Android提供了一个监听EditText的接口TextWatcher,通过调用EditText里的addTextChangedListener()方法实现监听。TextWatcher里面有三个要实现的方法,我试着根据源码里的注释解释一下三个方法的作用:

public interface TextWatcher extends NoCopySpan {

// 该方法被调用时说明在s中,从下标start开始的count个字符将要被替换为长度为after的字符串
    public void beforeTextChanged(CharSequence s, int start, int count, int after);

// 该方法被调用时说明在s中,从start开始的count个字符刚刚替换掉了长度为before的字符串
    public void onTextChanged(CharSequence s, int start, int before, int count);

// 该方法被调用时说明在s中的某个地方发生了字符变化
    public void afterTextChanged(Editable s);
}

我们要达到的目的是,字符数量满足要求以后执行某操作,字数不够时该操作变为不可执行,因此只需要重写afterTextChanged(Editable s)这个方法就好了。于是我封装了一个抽象类,留出两个抽象方法供使用者实现业务逻辑:

/**
 * @author evilyin(ChenZhixi)
 * @since 15/10/31
 */
public abstract class TextCountWatcher implements TextWatcher {
    //要求的字数
    private int count;

    public TextCountWatcher(int count) {
        this.count = count;
    }
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {

    }

    @Override
    public void afterTextChanged(Editable s) {
        if (s.length() >= count) {
            onTextMatchCount();
        }else if (s.length() < count) {
            onTextLessThanCount();
        }
    }

    // 当字数达到或超过要求时触发
    public abstract void onTextMatchCount();

    // 当字数不够时触发
    public abstract void onTextLessThanCount();
}

实际使用的例子,mobileNumber是输入手机号的EditText,必须输入11位,才可以点击边上的按钮:

mobileNumber.addTextChangedListener(new TextCountWatcher(11) {
    @Override
    public void onTextMatchCount() {
        canClick();
    }

    @Override
    public void onTextLessThanCount() {
        notClick();
    }
});

有的时候我们还想实现另一个功能,在某个输入框中输入的字数达到上限后就不能输入了,这同样可以通过TextWatcher实现。下面的代码在参考了网上的写法后自己做了些改进:

/**
 * @author evilyin(ChenZhixi)
 * @since 15/11/14
 */
public class TextLengthWatcher implements TextWatcher {
    private int length; //字数限制
    private EditText editText;
    private boolean onceLoad = true;

    public TextLengthWatcher(int length, EditText editText) {
        this.length = length;
        this.editText = editText;
    }

    @Override
    public void beforeTextChanged(CharSequence s, int start, int count, int after) {

    }

    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        int countSize = 0;
        Editable editable = editText.getText();
        String str = editable.toString();
        char[] array = str.toCharArray();
        if (onceLoad) {
            editText.setSelection(s.length());
            onceLoad = false;
        }
        for (int i = 0; i < array.length; i++) {
            if (StringUtil.isChineseChar(str.charAt(i)))/**判断是否为中文*/
            {
                countSize += 2;/**如果为中文或者中文特殊符号则占两个字节*/
            } else {
                countSize += 1;/**英文则占一个字节*/
            }
            if (countSize > length) {
                /**达到最大值*/
                int selEndIndex = Selection.getSelectionEnd(editable);
                str = editable.toString();
                String newStr = str.substring(0, i);
                editText.setText(newStr);
                editable = editText.getText();
                int newLen = editable.length();
                if (selEndIndex > newLen) {
                    selEndIndex = editable.length();
                }
                Selection.setSelection(editable, selEndIndex);
                editText.setTextColor(Color.RED);
                break;
            } else {
                editText.setTextColor(Color.BLACK);
            }
        }

    }

    @Override
    public void afterTextChanged(Editable s) {

    }

}

实际使用更方便,不需要实现抽象方法了:

commentEt.addTextChangedListener(new TextLengthWatcher(100, commentEt));

commentEt是评论框EditText,限制字数上限100个字符,在达到上限以后无法输入新的字符,并且字体颜色会变红。

嗯,就这么多了。