Exposed dropdown menusの実装

投稿日:  更新日:

Exposed dropdow menusの実装方法を紹介します。

スポンサーリンク

Exposed dropdown menusとは

EditText(文字入力を要求するView)の入力候補(Exposed:手持ちの札を陳列する)を表示するメニューです。
※AutoCompleteTextViewはEditTextを継承しています。

Material Design ComponentsのText fieldsカテゴリの方が機能的に近いと思いますが、何故かMenusに属しています。

スポンサーリンク

メニューの実装

Exposed drowdown menusの実装方法を示します。

サンプルの実装

入力候補を表示する機能はAutoCompleteTextViewが元から持っています。

AutoCompleteTextViewはメニュー表示に特化して開発されたクラスではありません。

Exposed dropdown menusは、このAutoCompleteTextViewをMaterial Designの指標に沿って装飾したものです。

メニューのレイアウト

メニューはTextInputLayoutの子ViewにAutoCompleteTextViewを配置した構成になります。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    ...
    tools:context=".MainActivity">

    <!-- 左上のメニュー -->
	<com.google.android.material.textfield.TextInputLayout
        android:id="@+id/txtInpLay"
        style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Item ?" ...>
		
        <AutoCompleteTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="none" />
			
    </com.google.android.material.textfield.TextInputLayout>

    <!-- 右下のメニュー -->
	<com.google.android.material.textfield.TextInputLayout>
        ...
    </com.google.android.material.textfield.TextInputLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

TextInputLayoutはLinearLayoutを継承していて、EditTextを一つだけ持つことが出来るコンテナタイプのViewです。※EditTextを二つ以上配置するとエラーになります。

このTextInputLayoutがMaterial Designの指標に沿った装飾を担っているラッパーです。

よって、Material Design ComponentsのMenusで紹介されているExposed dropdown menusは、必ず図のような構成になります。

ExposedPopupMenusの構成

メニューの部分はAutoCompleteTextViewが起動するListPopupWindowです。

ListPopupWindowはPopupWindow(パネルが浮き上がるような表示)とListView(アイテムを一覧表示)を組み合わせたものです。

メニューの組み込み

実装はListViewそのものです。

配列でメニューのアイテムを用意したので、ListAdapterにArrayAdapterを用いています。

メニューのアイテムをListAdapter経由で、AutoCompleteTextViewへ登録するだけです。

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:ellipsize="end"
    android:maxLines="1"
    android:textAppearance="?attr/textAppearanceSubtitle1" />
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ...

        val _items = arrayOf("Item 1", "Item 2", "Item 3")
        val _adapter = ArrayAdapter(this, R.layout.menu_item, _items)

        val _textInputlayout = findViewById<TextInputLayout>(R.id.txtInpLay)
        val _editText = _textInputlayout.editText as? AutoCompleteTextView
        _editText?.apply {
            setAdapter(_adapter)
            ...
        }
    }
}

カスタマイズは他のListAdapter(Simple/CursorAdapterなど)を使ったり、アイテムのレイアウトを変更したり、ListViewと同じ方法が使えそうです。

サンプルの実行結果

図は上記で実装したExposed dropdown menusの実行結果です。

Exposed dropdown menusの実行結果

TextInputLayout(クリックに反応するのはAutoCompleteTextView)をクリックすると、その下に左上を起点としたドロップダウンメニューが開いて、アイテムが現れます。

ドロップダウンメニューが画面の外へ出てしまうときは、メニュー全体が表示できる位置へ移動されます。

スポンサーリンク

アイテムのクリックイベント処理

AdapterView.OnItemClickListenerリスナーを実装し、AutoCompleteTextViewオブジェクトへ登録します。

アイテムのクリックが行われるとAdapterView.OnItemClickListenerにコールバックが返ってきます。

引数のpositionがクリックされたアイテムの位置を示しています。後は位置に基づいて処理を行います(サンプルはToastを発行)。

アイテムを一覧表示している部分はListViewなので、イベントの処理方法はListViewと全く同じです。

class MainActivity : AppCompatActivity() {
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
		...
        val _items = arrayOf("Item 1", "Item 2", "Item 3")
        val _adapter = ArrayAdapter(this, R.layout.menu_item, _items)

        val _textInputlayout = findViewById<TextInputLayout>(R.id.txtInpLay)
        val _editText = _textInputlayout.editText as? AutoCompleteTextView
        _editText?.apply {
            setAdapter(_adapter)
            setOnItemClickListener { parent, view, position, id ->
                val _item = parent.getItemAtPosition(position) as String
                when(position) {
                    0 -> {  // Item 1の処理
                        Toast.makeText(parent.context, _item, Toast.LENGTH_LONG)
                            .show() }
                    1 -> {  // Item 2の処理
                        Toast.makeText(parent.context, _item, Toast.LENGTH_LONG)
                            .show() }
                    2 -> {  // Item 3の処理
                        Toast.makeText(parent.context, _item, Toast.LENGTH_LONG)
                            .show() }
                    else -> {}
                }
            }
        }
		
		...
	}
}
スポンサーリンク

スタイルでデザインを変更

先にも述べましたが、TextInputLayoutがMaterial Designの指標に沿った装飾を担っているラッパーです。

TextInputLayoutのスタイルを変更すると、デザインが変えられるようになっています。

	<com.google.android.material.textfield.TextInputLayout
        android:id="@+id/txtInpLay"
        style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Item ?" ...>
		
        <AutoCompleteTextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inputType="none" />
			
    </com.google.android.material.textfield.TextInputLayout>
スタイル名
Widget.MaterialComponents.TextInputLayout.***
デザイン
FilledBox.ExposedDropdownMenuスタイルFilledBox
OutlinedBox.ExposedDropdownMenuスタイルOutlineBox
スポンサーリンク

関連記事:

Material Design ComponentsにMenusというカテゴリがあります。 「Menus(メニュー)」なので、言葉のとおり、選択する項目を一覧表示する機能です。 Menusはメニューの表現方法によって、幾つかの種類があります。 このMenusの種類と特徴を紹介します。 ...
スポンサーリンク