Edited at

AndroidのAutoCompleteTextViewで、常に全ての候補を一覧に表示する

More than 1 year has passed since last update.


概要

AndroidのAutoCompleteTextViewで、入力候補に全ての候補を一覧表示する方法について書いています。

AutoCompleteTextViewは、例えば通常は入力欄に"100"と入力した時、次の図のように100に一致する候補しか一覧に表示されません。

今回は、入力欄に"100"と入力しても、次のように全ての候補が表示されるようにします。

本環境は、Android 8.1、targetSdkVersion 26となっています。


用途

AutoCompleteTextViewは、入力中のテキストに対して、部分的に一致する候補をリストアップして選択させる自動補完機能を提供するためのViewです。あらかじめ候補一覧を示すAdapterをAutoCompleteTextViewに登録することで、入力中の文字にマッチする候補を表示させます。

ちなみに、TextViewと名付けられてはいますが、EditTextを継承しています。何故こんな紛らわしい名前付けたんでしょうか…。

今回、入力内容に関わらず全ての候補を一覧表示させる機能が欲しかったので、実装することにしました。要は、ユーザ入力可能なSpinnerのようなものが欲しかったということです。これにより、ユーザ入力の簡略化が期待できます。


方法

最初に、Filter (android.widget.Filter)を作成します。これは、ユーザの入力に対して、どう候補を絞り込むかを定義するものです。今回は一切絞り込まないようにするので、performFilteringで空のFilterResultsを返します。

class SampleArrayFilter extends Filter {

@Override
protected FilterResults performFiltering(CharSequence prefix) {
return new FilterResults();
}

@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.count > 0) {
notifyDataSetChanged();
} else {
notifyDataSetInvalidated();
}
}
}

次に、Adapterを作成します。ここでは、getFilterメソッドをオーバーライドして、先程作成したFilterを返します。(コンストラクタは適当)

class SampleArrayAdapter extends ArrayAdapter<String> {

public SampleArrayAdapter tArrayAdapter (@NonNull Context context, int textViewResourceId, @NonNull String[] objects) {
super(context, textViewResourceId, objects);
}

@Override
public Filter getFilter() {
return new SampleArrayFilter();
}
}

作成したAdapterを、AutoCompleteTextView に登録します。

String[] sampleArray = {"400", "300", "200", "100", "75", "50", "25"};

SampleArrayAdapter adapter = new SampleArrayAdapter (getContext(), android.R.layout.simple_dropdown_item_1line, sampleArray);
AutoCompleteTextView sammpleView = findViewById(R.id.sampleSpeedEditText);
sammpleView .setAdapter(adapter );

これにより、常に全ての候補を表示するAutoCompleteTextViewになります。


未入力でも候補を表示する

しかし、この状態ではまだ問題があります。AutoCompleteTextViewは、標準状態で2文字以上の入力に対して候補を表示します。これは、多数の候補が表示されないようにするためのものと思われます。これに対して、setThresholdで候補を表示するまでの文字数を指定することができますが、最小が1文字となるため、1文字入力しないと候補が表示されません。

今回は、ユーザ入力状態になった時点で全ての候補を表示して、テキスト入力・候補選択の両方を可能にすることで、入力を簡略化させることを目的としています。そのため、0文字でも表示させるようにしたいところです。

そこで、以下のようにイベント設定を行います。

sampleView.setThreshold(1);

sampleView.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
sampleView.showDropDown();
}
}
});
sampleView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
sampleView.showDropDown();
}
});

AutoCompleteTextViewのフォーカスおよびタップで、強制的に候補を表示させます。今回は2つのイベント両方に対して設定しましたが、UIや画面の構成によってはどちらかでも良いかと思います。

この方法とは別に、AutoCompleteTextViewを継承したクラスを作成する方法があるようです。この場合、enoughToFilterをオーバーライドして、setThresholdの値を無視して必ずtrueを返すようにします。(とは書いてみたものの、自分は試していないのですが。)


最後に

そんな感じで、入力、選択両方が可能なAutoCompleteTextViewを実装してみました。多少不格好な感じもしますが、概ね目的のViewは作れたように思います。

個人的には、この程度のViewは標準で用意して欲しいなぁ、と思わないでもないです。Androidの標準のViewは、痒いところに手が届かないパターンが多すぎて…。


参考