はじめに
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 はなんでクラッシュするんだろう??わかりません!!
  
  
  
  



コメント