AutoCompleteAdapter
AutoCompleteTextViewで使用するためのAdapter。
AutoCompleteTextViewは、単純に選択肢を表示するだけならArrayAdapterを使うと楽だが、ビューをカスタマイズしようとすると途端にややこしくなる。
自分で作ってていろいろハマッたので、そこらへんをラップしたクラスを作った。
基本、3つのメソッドをオーバーライドするだけで使えるはず。
あまり意味は無いが、ArrayAdapterと同じような動作をさせるコードはこんな感じ。
public class SampleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // mainはAutoCompleteTextViewが1つあるだけのレイアウト setContentView(R.layout.main); AutoCompleteTextView t = (AutoCompleteTextView) findViewById(R.id.AutoCompleteTextView01); // keywordsは適当な文字列の配列リソース t.setAdapter(new AutoCompleteAdapter<String>(Arrays.asList(getResources().getStringArray(R.array.keywords))) { @Override protected View createView(int i) { return LayoutInflater.from(SampleActivity.this).inflate(android.R.layout.simple_list_item_1, null); } @Override protected boolean isMatch(CharSequence input, String item) { return item.startsWith(input.toString()); } @Override protected void refreshView(int i, View view) { ((TextView)view).setText((CharSequence) getItem(i)); } }); } }
/** * AutoCompleteTextView用のAdapter * * @param <V> リストに含まれるアイテムの型 */ public abstract class AutoCompleteAdapter<V> extends BaseAdapter implements Filterable { private List<V> allItems; private List<V> filterdItems; private boolean alwaysCreateView; /** * すべてのアイテムで共通のビューを使う場合のコンストラクタ * @param items すべての選択肢のリスト */ public AutoCompleteAdapter(List<V> items) { this(items, false); } /** * ビューの生成タイミングを指定する場合のコンストラクタ * @param items すべての選択肢のリスト * @param alwaysCreateView {@link #createView(int)}参照 */ public AutoCompleteAdapter(List<V> items, boolean alwaysCreateView) { this.allItems = items; this.alwaysCreateView = alwaysCreateView; } /** * アイテムの表示に使用するビューを作成する。<br/> * コンストラクタのalwaysCreateView引数がtrueであれば、アイテムを表示するたびに呼ばれる。<br/> * コンストラクタのalwaysCreateView引数がfalseであれば、必要に応じて呼ばれる。(一つのビューが複数のアイテムで使いまわされることがある) * @param i 表示するアイテムのインデックス * @return */ protected abstract View createView(int i); /** * ビューの内容を更新する * @param i 表示するアイテムのインデックス * @param view 表示に使用するビュー */ protected abstract void refreshView(int i, View view); /** * アイテムを選択肢に表示するか否かを返す * @param input AutoCompleteTextViewに入力された文字列 * @param item 比較対象のアイテム * @return trueであればitemが選択肢に表示される */ protected abstract boolean isMatch(CharSequence input, V item); /** * @see ListAdapter#getCount() */ public int getCount() { return filterdItems.size(); } /** * @see ListAdapter#getItem(int) */ public Object getItem(int i) { return filterdItems.get(i); } /** * @see ListAdapter#getItemId(int) */ public long getItemId(int i) { return i; } /** * @see ListAdapter#getView(int, View, ViewGroup) */ public View getView(int i, View view, ViewGroup viewgroup) { // ビューが作成されていないか、アイテムごとに異なるビューを使用する場合は新たにビューを作成する if (view == null || alwaysCreateView) { view = createView(i); } // アイテムの内容をビューに反映する refreshView(i, view); return view; } /** * @see Filterable#getFilter() */ public Filter getFilter() { return new Filter() { @Override protected FilterResults performFiltering(CharSequence charsequence) { FilterResults ret = new FilterResults(); List<V> list = new ArrayList<V>(); if (charsequence == null) { // 文字が入力されていなければすべての選択肢を表示する // 実質不要? list.addAll(allItems); } else { // アイテムごとに選択肢に表示するか否かを判定する for (V item : allItems) { if (isMatch(charsequence, item)) { list.add(item); } } } ret.values = list; ret.count = list.size(); return ret; } @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence charsequence, FilterResults filterresults) { filterdItems = (List<V>) filterresults.values; if (filterresults != null && filterresults.count > 0) { notifyDataSetChanged(); } else { notifyDataSetInvalidated(); } } }; } }