【Android】DialogFragmentの背景を透過しようとしてハマった話
この記事の内容
DialogFragmentの背景を透過しようとしたらハマったので、調べたことのまとめ
・dialog.window().setBackgroundDrawableResource()で透過できる
・onCreateDialog()では、dialogがnullになる
・DialogFragmentとlifecycleの話
やりたいこと
dialogFragmentで表れる余白のbackgroundを透明にしたい。
Before → After
試したこと
とりあえずstack overflow を検索するとピッタリなやつがあった。
dialogの"setBackgroundDrawable()"メソッドで透過背景を指定すればいいらしい。簡単そう。
Answer : Add this code.
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent)
さっそく試して実行してみる。
class HogeDialogFragmnet: DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
//背景を透過する処理
dialog!!.window!!.setBackgroundDrawableResource(android.R.color.transparent)
val builder = AlertDialog.Builder(activity)
//レイアウトの処理は割愛
return builder.create()
}
}
ダメでした。
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.kabos.sample, PID: 2681
java.lang.NullPointerException
DialogFragmentのソースコードを確認してみる
dialogインスタンスがnullになってエラーがでてしまいました。
onCreateDialogで取得しようとしたのがマズかったかもしれない仮説が浮上したので
DialogFragmentのソースコードを確認してみました。
public class DialogFragment extends Fragment
implements DialogInterface.OnCancelListener, DialogInterface.OnDismissListener {
//③getDialog()でメンバー変数のDialogインスタンスを取得する
@Nullable
public Dialog getDialog() {
return mDialog;
}
//②DialogインスタンスはonGetLayoutInflater()の中で、onCreateDialog()から取得している
@Override
@NonNull
public LayoutInflater onGetLayoutInflater(@Nullable Bundle savedInstanceState) {
LayoutInflater layoutInflater = super.onGetLayoutInflater(savedInstanceState);
if (!mShowsDialog || mCreatingDialog) {
return layoutInflater;
}
try {
mCreatingDialog = true;
mDialog = onCreateDialog(savedInstanceState);//←ココ
setupDialog(mDialog, mStyle);
} finally {
mCreatingDialog = false;
}
return layoutInflater.cloneInContext(requireDialog().getContext());
}
//①onCreateDialogで初めてDialogがインスタンス化される
@MainThread
@NonNull
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
return new Dialog(requireContext(), getTheme());
}
}
確認してみたところ、dialogがインスタンス化されるのは、onCreateDialog()のタイミングになっていました。
自分の最初のコードではonCreateDialog()の中でdialogを参照していたので、nullになったようです。
そのため、onCreateDialog()よりも後のタイミングである以下のタイミングで呼び出す必要があります。
・onCreateView()
・onStart()
またDialogFragmentはfragmentを継承しているので、Fragmentと同様のライフサイクルになります。
・onCreate() / onCreateDialog()
・onCreateView()
・onStart()
・onResume()
以下のように、dialogにアクセスするタイミングを変えると、当初の目的通り背景が透過されます。
class HogeDialogFragmnet: DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
//レイアウトの処理は割愛
}
override fun onStart() {
super.onStart()
//dialogはonCreateDialogでインスタンス化されたので、アクセスできる
dialog!!.window!!.setBackgroundDrawableResource(android.R.color.transparent)
}
}
まとめ
・dialog.window().setBackgroundDrawableResource()でdialogの背景を透過できる
・dialogはonCreateDialog()でインスタンス化されるので、それより後にアクセスする
ライフサイクルについて曖昧な理解のままだったので、ライフサイクルについて学ぶいい機会になりました。
Author And Source
この問題について(【Android】DialogFragmentの背景を透過しようとしてハマった話), 我々は、より多くの情報をここで見つけました https://qiita.com/KabosDeer/items/feed87e6ecb4e46fd3d1著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .