はじめに
Android のダイアログとかポップぽいものを Popup としてまとめました。その2!!
今回は PopupWindow と ListPopupWindow について!
ソースは github にあげてます↓↓↓
ソース(github)
PopupWindow
指定の View を Popup で表示するやつ。(たぶん iOS でいうポップオーバーだと思う)
実装
xml で表示したい View を作成して PopupWindow
の contentView
に設定し、幅、高さ、背景などを指定して showAsDropDown
か showAtLocation
で表示する。
popup_window.xml(PopupWindowで表示するView)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" android:padding="16dp"> <ImageView android:layout_width="32dp" android:layout_height="32dp" app:srcCompat="@android:mipmap/sym_def_app_icon" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="PopupWindow" /> </LinearLayout> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:text="TextView" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="16dp" android:layout_marginBottom="16dp" android:layout_marginStart="16dp" android:layout_marginEnd="16dp" android:text="Dismiss" android:layout_gravity="center_horizontal" /> </LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout> |
popup_background.xml(PopupWindowの背景用)
1 2 3 4 5 6 7 8 |
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="@android:color/white" /> <stroke android:width="2dp" android:color="@android:color/black" /> </shape> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
val inflater = layoutInflater val popView = inflater.inflate(R.layout.popup_window, null) PopupWindow().also { popupWindow -> popView.findViewById<TextView>(R.id.text).text = text popView.findViewById<Button>(R.id.button).setOnClickListener { popupWindow.dismiss() } popupWindow.contentView = popView popupWindow.setBackgroundDrawable(ResourcesCompat.getDrawable(resources, R.drawable.popup_background, null)) popupWindow.width = ViewGroup.LayoutParams.WRAP_CONTENT popupWindow.height = ViewGroup.LayoutParams.WRAP_CONTENT // こいつらがないとpop表示中も背景タップができる popupWindow.isFocusable = true popupWindow.isOutsideTouchable = true popupWindow.showAsDropDown(button) // ボタンなど渡す // showAtLocationの場合はこんな感じ // popupWindow.showAtLocation(findViewById(R.id.root), Gravity.CENTER, 0, 0) } |
下記のように表示・非表示のアニメーション設定ができる
1 2 |
popupWindow.enterTransition = Slide(Gravity.LEFT) popupWindow.exitTransition = Slide(Gravity.RIGHT) |
注意事項
PopupWindow
の使用にはいくつか注意事項がある
幅・高さの指定
幅と高さの指定は dp に変換する必要があるので下記のように指定する。
1 2 3 4 5 6 7 8 9 10 11 12 |
val width = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 240f, resources.displayMetrics ) val height = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, 200f, resources.displayMetrics ) popupWindow.width = width.toInt() popupWindow.height = height.toInt() |
クラッシュ防止
下記を指定していない場合、バックボタンで Activity が終了しその際に android.view.WindowLeaked
でクラッシュしてしまう。。。
1 2 |
popupWindow.isFocusable = true popupWindow.isOutsideTouchable = true |
対策として PopupWindow
をメンバ変数で保持して onDestroy
で dismiss
してやる。
1 2 3 4 5 6 7 8 9 |
override fun onDestroy() { super.onDestroy() // DismissせずにActivity終了するとクラッシュする popupWindow?.also { if (it.isShowing) { it.dismiss() } } } |
参考
- Android デベロッパー: PopupWindow
- PopupWindowで画面内にダイアログ風の表示をする方法
- 【AndroidのViewを制する】 PopupWindowを使いこなしてポップアップを表示する
- 【AndroidのViewを制する】 PopupWindowを任意の位置に表示する
- 【AndroidのViewを制する】 表示中のPopupWindowを更新する
- 【AndroidのViewを制する】 表示中のPopupWindowの設定を更新する
- 【AndroidのViewを制する】 PopupWindowの設定を変更するメソッド群1
- 【AndroidのViewを制する】 PopupWindowの設定を変更するメソッド群2
ListPopupWindow
ListView
を Popup 表示するやつ。ドロップダウン用??(Spinner
との使い分けはなんだろう??)
通常 | カスタム1 | カスタム2 |
---|---|---|
実装
簡易実装
1 2 3 4 5 6 7 8 9 10 11 12 |
ListPopupWindow(this).also { val list = listOf("Dialog", "PopupWindow", "ListPopupWindow", "Toast", "SnackBar", "Menu") val adapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, list) it.setAdapter(adapter) it.setOnItemClickListener { _, _, position, _ -> val text = adapter.getItem(position) Toast.makeText(this, text, Toast.LENGTH_SHORT).show() it.dismiss() } it.anchorView = button // ボタンなど渡す it.show() } |
カスタム色々
View表示
setPromptView
でリストの上か下に View
を表示できる。デフォルトは上に表示で下に表示したい場合は promptPosition
に ListPopupWindow.POSITION_PROMPT_BELOW
を設定する。
1 2 3 4 |
val imageView = ImageView(this) imageView.setImageResource(R.drawable.ic_launcher_foreground) popupWindow.setPromptView(imageView) popupWindow.promptPosition = ListPopupWindow.POSITION_PROMPT_BELOW |
表示位置調整
verticalOffset
と horizontalOffset
で表示位置を調整できる。たぶん Gravity
はない。
1 2 |
popupWindow.verticalOffset = 80 popupWindow.horizontalOffset = 80 |
背景設定
PopupWindow
同様 setBackgroundDrawable
で背景を設定できる
1 |
popupWindow.setBackgroundDrawable(ResourcesCompat.getDrawable(resources, R.drawable.popup_background, null)) |
注意事項
PopupWindow
と同様。幅・高さの設定は dp 変換が必要。クラッシュ防止は onDestroy
で dismiss
してもクラッシュしてしまった。。。
とりあえず生成時に渡す Context
を Activity
から applicationContext
にしたらクラッシュしなくなったけどたぶんこの解決策は違うと思う。。。
参考
- Android デベロッパー: ListPopupWindow
- 【AndroidのViewを制する】 ListPopupWindowを使いこなしてポップアップを表示する
- 【AndroidのViewを制する】 ListPopupWindowのポップアップ表示を調整する
- 【AndroidのViewを制する】 ListPopupWindowでユーザ操作を受け付ける
- 【AndroidのViewを制する】 ListPopupWindowの設定を変更する
おわりに
PopupWindow
がわりと使い勝手よさそうだけどメンバ変数に持つのがなんかやだなぁ。ListPopupWindow
はなんでクラッシュするんだろう??わかりません!!
コメント