TextViewのmaxLengthのサロゲートペア対応(絵文字に対応した文字数制限)


AndroidのTextViewやEditTextはレイアウトXMLでmaxLengthを指定することで入力文字数を制限することができます。
しかし、Unicodeのサロゲートペアで表現される絵文字などは、2文字分として判定されてしまうため、正確な制限ができません。
maxLengthはandroid.text.InputFilter.LengthFilterで実現されています。
これを改造してサロゲートペアに対応することで、正確な入力文字数制限を実現しました。


import android.text.InputFilter;
import android.text.Spanned;

/**
 * サロゲートペア対応版のLengthFilter
 */
public class InputLengthFilter implements InputFilter {
    private final int mMax;

    public InputLengthFilter(int max) {
        mMax = max;
    }

    public CharSequence filter(CharSequence source, int start, int end, Spanned dest,
                               int dstart, int dend) {
        int realLen = dest.toString().codePointCount(0, dest.length());
        int keep = mMax - (realLen - (dend - dstart));
        if (keep <= 0) {
            return "";
        } else if (keep >= end - start) {
            return null; // keep original
        } else {
            keep += start;
            if (Character.isHighSurrogate(source.charAt(keep - 1))) {
                return source.subSequence(start, keep + 1);
            }
            return source.subSequence(start, keep);
        }
    }

    public int getMax() {
        return mMax;
    }
}

TextField#setFilters()に上記のクラスのインスタンスを渡すことで文字数を制限できます。