EditableとInputFilter
Androidの文字入力に使用するウィジェットであるEditTextクラスでは、文字列の格納のためのプロパティである"Text"に、StringではなくEditableという独自のインタフェースを使用している。
@Override public Editable getText() { return (Editable) super.getText(); } @Override public void setText(CharSequence text, BufferType type) { super.setText(text, BufferType.EDITABLE); }
わざわざ別なインタフェースを介しているのは、いろいろな理由があるからだが、そのうちの一つはViewに表示/入力される文字列に対してなんらかの前処理、後処理を施すためだ。
Editableに実装されているInputFilterインタフェース配列のプロパティ"Filters"は、その名の通り、Editableに何らかのフィルタを施すことを可能とする。
- android.text.Editableより
public void setFilters(InputFilter filters);
public InputFilter getFilters();
InputFilterインタフェースには只一つのfilterメソッドが宣言されている。
- android.text.InputFilter
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend);
使い方は簡単で、用途に合わせたフィルタメソッドを実装したフィルタをEditableにセットするだけだ。同インタフェースには内部クラスとして、既にInputFilterの2つの実装例が公開されており、これを参考にするのが一番手っ取り早い。
- InputFilterの実装例 ( InputFilter.AllCaps )
public static class AllCaps implements InputFilter { public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) { for (int i = start; i < end; i++) { if (Character.isLowerCase(source.charAt(i))) { char[] v = new char[end - start]; TextUtils.getChars(source, start, end, v, 0); String s = new String(v).toUpperCase(); if (source instanceof Spanned) { SpannableString sp = new SpannableString(s); TextUtils.copySpansFrom((Spanned) source, start, end, null, sp, 0); return sp; } else { return s; } } } return null; // keep original } }
InputFilter.AllCapsクラスはソースの文字列を全てUpperCase(大文字)に変換するフィルタだ。
ちなみにEditTextのスーパークラスであるTextViewクラスでは、直接内部にフィールドでInputFilter[]を保持し、これをプロパティとして公開しているが、内部ではmTextフィールド(Editable)にフィルタを設定しているので、通常はこちらを使うことになるだろう。
public void setFilters(InputFilter[] filters) { if (filters == null) { throw new IllegalArgumentException(); } mFilters = filters; if (mText instanceof Editable) { setFilters((Editable) mText, filters); } }
なお、プロパティとしてはサポートされていないが、レイアウトXMLでのViewの属性"maxlengthを"を設定すると、内部で桁数制限を実装するInputFilter.LengthFilterをインストールする。
if (maxlength >= 0) { setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxlength) }); } else { setFilters(NO_FILTERS); }
この例のようにプロパティでは公開されていないがXML属性ではサポートされている属性が結構あるのも、ちぐはぐな感じが否めない。
どうやらViewのInputFilterは、JFC/SwingのJComponentにおけるDocumentFilterとほぼ同じ感覚で使えそうだ。