List popup window menusの実装方法を紹介します。
ターゲットViewをクリックすることで、アンカーViewの下に表示されるメニューです。
※表示例はターゲット=アンカーViewになっています。
メニューの実態はApi 11で追加されたListPopupWindowクラスです。
ListPopupWindowはPopupWindow(パネルが浮き上がるような表示)とListView(アイテムを一覧表示)を組み合わせたもので、メニュー表示に特化して開発されたクラスではありません。
しかし、メニューと同等な振る舞いが期待できます。
Material Design ComponentsのMenusカテゴリに属し、メニューの表現方法の一つとして紹介されています。
アイテムを一覧表示する部分がListViewなので、メニューアイテムの指定にandroid.widget.ListAdapterを用いる点が大きな特徴です。
※現在(’21.08)ListViewはレガシー扱い、単独での使用は推奨されません。
メニューの実装
実装はListViewそのものです。
サンプルの実装
配列でメニューのアイテムを用意したので、ListAdapterにArrayAdapterを用いています。
メニューのアイテムをListAdapter経由で、ListPopupWindow内のListViewへ登録するだけです。
<?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) ... // ViewのクリックでList popup window menusを起動 findViewById<Button>(R.id.btnSLT).setOnClickListener { openMenu(it) } findViewById<Button>(R.id.btnSRB).setOnClickListener { openMenu(it) } } fun openMenu(anchor: View) { val _items = arrayOf("Item 1", "Item 2", "Item 3") val _adapter = ArrayAdapter(this, R.layout.menu_item, _items) val _popup = ListPopupWindow(this) _popup.setAdapter(_adapter) _popup.setOnItemClickListener { parent, view, position, id -> _popup.dismiss() // アイテムのクリックで自身を閉じる } _popup.anchorView = anchor _popup.show() } }
注意点として、メニューのアイテムがクリックされた時に、自身を閉じる必要があります。ListPopupWindow#dissmiss( )が閉じる処理を行ってい部分です。
カスタマイズは他のListAdapter(Simple/CursorAdapterなど)を使ったり、アイテムのレイアウトを変更したり、ListViewと同じ方法が使えそうです。
サンプルの実行結果
図は上記で実装したList popup window menusの実行結果です。
ターゲットViewをクリックすると、アンカーViewの下に左上を起点としたドロップダウンメニューが開いて、アイテムが現れます。ちなみに、サンプルはターゲット=アンカーViewになっています。
ドロップダウンメニューが画面の外へ出てしまうときは、メニュー全体が表示できる位置へ移動されます。
アイテムのクリックイベント処理
AdapterView.OnItemClickListenerリスナーを実装し、ListPopupWindowオブジェクトへ登録します。
アイテムのクリックが行われるとAdapterView.OnItemClickListenerにコールバックが返ってきます。
引数のpositionがクリックされたアイテムの位置を示しています。後は位置に基づいて処理を行います(サンプルはToastを発行)。
アイテムを一覧表示している部分はListViewなので、イベントの処理方法はListViewと全く同じです。
class MainActivity : AppCompatActivity() { ... fun openMenu(anchor: View) { val _items = arrayOf("Item 1", "Item 2", "Item 3") val _adapter = ArrayAdapter(this, R.layout.menu_item, _items) val _popup = ListPopupWindow(this) _popup.anchorView = anchor _popup.setAdapter(_adapter) _popup.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 -> {} } _popup.dismiss() } _popup.show() } }
関連記事: