【Android】~ちょこメモ~ダイアログ「画面外タップで閉じる」操作を無効化する
はじめに
今回の「ちょこっとメモ」、
自分の語彙力だとタイトルがどうしても長くなってしまうので
断腸の思いで「ちょこメモ」に改名しました…(´;ω;`)笑
ダイアログの実装方法について知りたい方は、
こちらの記事をご覧ください
ukit-labo.hateblo.jp
調べたきっかけは、今現在開発中の個人アプリで
「”OK”か”NG”か、必ずどちらかを選択するダイアログ」
を作成したい場面が出てきた時でした。
まずは、場面を想像しやすいように
サンプルコードを紹介します。
サンプルコード
今回題材として使用するサンプルコードです。
activity_main.xml
まずは、アクティビティです。
ボタンのみです。YES。
<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" tools:context=".MainActivity"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onDialogButtonClick" android:text="@string/btn_dialog" app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout>
SampleDialogFragment.kt
次に、「ダイアログ」を表すクラスです。
どちらのボタンが押されたかをトーストで表示する、という
極限までシンプルなダイアログにしました。
class SampleDialogFragment: DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(activity) builder.setTitle("サンプル") builder.setPositiveButton("OK"){_, _ -> Toast.makeText(context, "OKボタンが押されました", Toast.LENGTH_LONG).show() } builder.setNegativeButton("NG"){_, _ -> Toast.makeText(context, "NGボタンが押されました", Toast.LENGTH_LONG).show() } return builder.create() } }
MainActivity.kt
最後にアクティビティクラスです。
ボタンを押すとダイアログを表示するプログラム
だけですね笑
超シンプル。
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun onDialogButtonClick(view: View){ val dialog = SampleDialogFragment() dialog.show(supportFragmentManager, "SampleDialogFragment") } }
問題点
私がこのダイアログに求める挙動は
「”OK”か”NG”、どちらかを必ず選択する」、
要するに
「キャンセル操作を無効化する」
というものでした。
しかし現在(デフォルト)の挙動では、
ダイアログ画面外をタップすると、ダイアログが閉じてしまいます。
これは、ダイアログ生成時にsetNeutralButton()をして
「キャンセルボタン」を作っていなくても、
「キャンセルは可能」
ということになります。
これじゃあ思った通りの実装ができないめぅ(;_;)
ってことです(?)
解決策
ダイアログフラグメントに対して
「isCancelable() = false」とします。
isCancelable()メソッドは
「ダイアログのキャンセル操作の有効・無効」をboolean値で設定します。
①ダイアログクラスに記述するパターン
class SampleDialogFragment: DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val builder = AlertDialog.Builder(activity) builder.setTitle("サンプル") builder.setPositiveButton("OK"){_, _ -> Toast.makeText(context, "OKボタンが押されました", Toast.LENGTH_LONG).show() } builder.setNegativeButton("NG"){_, _ -> Toast.makeText(context, "NGボタンが押されました", Toast.LENGTH_LONG).show() } //↓↓これを追加する。 this.isCancelable = false return builder.create() } }
もしくは、
②ダイアログを呼び出した側に記述するパターン
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun onDialogButtonClick(view: View){ val dialog = SampleDialogFragment() //↓↓これを追加する dialog.isCancelable = false dialog.show(supportFragmentManager, "SampleDialogFragment") } }
ポイント
まず
「①ダイアログクラスに追加するパターン」について
記述場所は
- onCreateDialog()の中
- return の前
そして、
- 「this」に対して
isCalcelable()を呼び出していることがポイントです。
この場合の「this」は”DialogFragment”であり、
生成する"AlertDialog"または"AlertDialog.Builder"ではありません。
次に
「②ダイアログを呼び出した側に記述するパターン」です。
生成したSampleDialogFragmentのインスタンスに対して、isCalcelable()を設定しています。
”SampleDialogFragment”は”DialogFragment”を継承しているため、
タイミングが違うだけで
やっていることは①と同じですね。
使い分けとしては、
ダイアログクラスから同じダイアログしか生成しない場合は
①のパターン。
ダイアログクラスを使いまわして使用する場合、キャンセル操作を個々で設定したい場合などは
②のパターン。
ってな感じで使えばいいんじゃないでしょうか。
注意点
この操作では、
生成したダイアログのすべてのキャンセル操作を無効にします。
つまり、
「”戻るボタン”によるキャンセル操作」
も無効になってしますの注意しましょう!