2010年9月26日日曜日

EditText の入力イベントを拾いたい

最近少々苦労したのでまとめておきます。


何がしたかったかというと、候補の表示。

入力しながら候補を絞ってリストを表示し、クリックできるようにするあれ。


初めは OnKeyListener を使ってやってみようと考えたんですが、
なんだか動作が不安定?

というか、IME の決定がされないとイベント拾わないくさい…


で、調べてみると AutoCompleteTextView なるものを発見。


これ、ListView みたいに Adapter をセットしておくと、この候補の一覧を
その中から作ってくれるという代物。超便利!


どうやるかというと、AutoCompleteTextView の方は特に気にせず普通の
EditText のように使えばOK。

ただ、Adapter の方に一工夫が要ります。

とはいっても、Filterable を implements するだけ。

getFilter というメソッドを実装します。

これは Adapter オブジェクトがセットされたときに呼び出されるようです。

【例】
こんなクラスを用意する(Adapterの実装はしてね)
public class XAdapter extends BaseAdapter implements Filterable {
public int getCount() {
}
public Object getItem(int position) {
}
public long getItemId(int position) {
}
public View getView(int posi, View convertView, ViewGroup parent) {
}
public Filter getFilter() {
Filter f = new Filter() {
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results != null && results.count > 0) {
//再描画させる
notifyDataSetChanged();
}
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
if(constraint==null)return null;
String ck = constraint.toString().toLowerCase();
FilterResults filterResults = new FilterResults();
ArrayList<String> it = new ArrayList<String>();
for(String v : StringListAdapter.this.baseitems){
if(v.toLowerCase().contains(ck))it.add(v);
}
StringListAdapter.this.items = it;
filterResults.values = it;//フィルタリング結果オブジェクト
filterResults.count = it.size();//フィルタリング結果件数
return filterResults;
}
};
return f;
}

}
で、こうする
AutoCompleteTextView txt = new AutoCompleteTextView(context);
XAdapter xa = new XAdapter();
txt.setAdapter(xa);


getFilter の戻り値として android.widget.Filter オブジェクトを返す必要が
あります。

Filter オブジェクトは performFiltering と publishResults を実装する必要があります。


performFiltering は入力値を引数に持ち、FilterResults を戻り値として返す必要が
あります。

これはテキストが編集されるたびに呼び出され、FilterResults の value 値と count 値
に基づいてリストを作成します。ただし、引数の CharSequence は最初の1文字目の
入力の際にnull で渡される(HTC Desire で確認)ので null 参照に注意してください。


publishResults は performFiltering の後に呼び出されます。

performFiltering で作成された FilterResults が引数として追加で渡されますので、
入力値と合わせてリストの再描画が必要な場合はここで notifyDataSetChanged
を呼び出してください。


ここまで実装した Adapter を AutoCompleteTextView に setAdapter してやれば
おそらくお望みのUIが完成するはずです。



ただ、ここで問題が発生しました。

検索結果を表示して別機能を呼び出すUIが欲しくなったんです。

そうなるとやっぱり EditText で AutoCompleteTextView みたいなイベントの
拾い方が出来ないとダメなんですよね。

と思ったらすぐ見つかりました。

addTextChangedListener で TextWatcher の実装をセットするという方法。


【例】
TextWatcherの実装を作成
private TextWatcher xTextListener = new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
}
public void afterTextChanged(Editable s) {
rewriteList(s);//入力文字を使用してリストを再描画
}
};
これをセットするだけ
EditText txt = (EditText)findViewById(R.id.text);
txt.addTextChangedListener(xTextListener);


メソッドリストですぐ「set」って打っちゃってたんで気付かなかった。。。

これ使えば AutoCompleteTextView のようなタイミングでさらに複雑なUIを
作成することができました。


無駄を省くためのいつもの癖が仇となりました…。
ちょっと反省。。。

0 件のコメント:

コメントを投稿