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

# 概要

Androidの[AutoCompleteTextView](https://developer.android.com/reference/android/widget/AutoCompleteTextView)で、入力候補に全ての候補を一覧表示する方法について書いています。

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

![1.png](https://qiita-image-store.s3.amazonaws.com/0/78503/02f42728-73ff-da43-fc4e-2ee34436121b.png)

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

![2.png](https://qiita-image-store.s3.amazonaws.com/0/78503/5d213a39-160d-1562-51b2-e7d3530ea1a4.png)

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

# 用途

AutoCompleteTextViewは、入力中のテキストに対して、部分的に一致する候補をリストアップして選択させる自動補完機能を提供するためのViewです。あらかじめ候補一覧を示すAdapterをAutoCompleteTextViewに登録することで、入力中の文字にマッチする候補を表示させます。
ちなみに、TextViewと名付けられてはいますが、[EditText](https://developer.android.com/reference/android/widget/EditText)を継承しています。何故こんな紛らわしい名前付けたんでしょうか…。
今回、入力内容に関わらず全ての候補を一覧表示させる機能が欲しかったので、実装することにしました。要は、ユーザ入力可能な[Spinner](https://developer.android.com/guide/topics/ui/controls/spinner)のようなものが欲しかったということです。これにより、ユーザ入力の簡略化が期待できます。

# 方法

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

~~~java
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を返します。（コンストラクタは適当）

~~~java
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 に登録します。

~~~java
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文字でも表示させるようにしたいところです。

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

~~~java
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は、痒いところに手が届かないパターンが多すぎて…。

# 参考

* AutoCompleteTextViewの仕組みを調べる - Qiita  
  https://qiita.com/Horie1024/items/d52ef21c589b135b5c37
* EditText with a Popup List  
  http://maogm.com/blog/edittext-with-popuplist-en.html
* listview - Custom filtering in Android using ArrayAdapter - Stack Overflow  
  https://stackoverflow.com/questions/2718202/custom-filtering-in-android-using-arrayadapter
* java - AutoCompleteTextView force to show all items - Stack Overflow  
  https://stackoverflow.com/questions/11284368/autocompletetextview-force-to-show-all-items/11302820
* android - Show all items in AutocompleteTextView without writing text - Stack Overflow
  https://stackoverflow.com/questions/15544943/show-all-items-in-autocompletetextview-without-writing-text