Fragment
アプリにを表示するがありますDialogFragment
。
フラグメントには、ダイアログを閉じるボタンがあります。しかし、dialogFragmentを表示すると、ダイアログの外側のタッチは何も行わず、ダイアログフラグメントの外側のボタンをクリックできません。
DialogFragmentの外部タッチを許可するにはどうすればよいですか?
Fragment
アプリにを表示するがありますDialogFragment
。
フラグメントには、ダイアログを閉じるボタンがあります。しかし、dialogFragmentを表示すると、ダイアログの外側のタッチは何も行わず、ダイアログフラグメントの外側のボタンをクリックできません。
DialogFragmentの外部タッチを許可するにはどうすればよいですか?
そのためにはWindow
、外側のタッチを許可するフラグをオンにし、見栄えを良くするために背景の薄暗いフラグをクリアする必要があります。
ダイアログの作成後に実行する必要があるため、を使用して実装しましたHandler
。
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// This is done in a post() since the dialog must be drawn before locating.
getView().post(new Runnable() {
@Override
public void run() {
Window dialogWindow = getDialog().getWindow();
// Make the dialog possible to be outside touch
dialogWindow.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
dialogWindow.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
getView().invalidate();
}
});
}
この時点で、外部との接触が可能です。
フレームなしでより良いものにしたい場合は、次のコードを追加できます。
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide title of the dialog
setStyle(STYLE_NO_FRAME, 0);
}
これは、タッチアクションだけでなく任意のアクションを許可するためのより一般的なフラグです
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
私は、外でのタッチでの解雇を処理する別の方法を見つけました。以下のコードサンプルを確認してください。間違いなく機能します。
@Override
public void onStart() {
// mDialogView is member variable
mDialogView = getView();
mDialogView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
float eventX = event.getRawX();
float eventY = event.getRawY();
int location[] = new int[2];
mDialogView.getLocationOnScreen(location);
if (eventX < location[0] || eventX > (location[0] + mDialogView.getWidth()) || eventY < location[1]
|| eventY > location[1] + mDialogView.getHeight()) {
dismiss();
return true;
}
return false;
}
});
}
私の場合、getDialog()をnull値ではなく取得していましたが、getDialog()。dismiss()が機能していませんでした。また、私の場合、右上にマークされているソリューションも機能しませんでした。それで、私はこのアプローチを取りました。
私は受け入れられた(Yanivの)答えをテストしました
Galaxy Tab A 9.7 Android 7.1.1: ok
Galaxy Tab A 8.0 Android 7 : ok
Galaxy Tab S4 Android 9 : no touch outside DialogFragment
Galaxy S5 Android 6.0.1 : ok
Galaxy Tab S2 Android 7 : ok
Galaxy Tab S3 Android 9 : no touch outside DialogFragment
Galaxy Tab S4 Android 9 : no touch outside DialogFragment
Galaxy Note Edge Android 6.0.1: ok
Galaxy Note4 Android 6.0.1 : ok
Android 9では機能しないようです。「機能しない」とは、DialogFragmentの外部にあるボタンをクリックしようとすると、onClick()メソッドがまったく呼び出されないことを意味します。
編集:私の発見に照らして(コメントで)私は以下が受け入れられた答えであるべきだと思います。以下は、エミュレーター、Google Pixel 6、LG Nexus 5X、HTC Desire 12、約5台のHuawei電話、Android5から10まですべてを実行する約20台のSamsung電話など、私がテストしたすべての場所で機能します。
public Dialog onCreateDialog(Bundle savedInstanceState)
{
FragmentActivity act = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(act);
// ... do your stuff here....
Dialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
Window window = dialog.getWindow();
if( window!=null )
{
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
return dialog;
}
上記の私の小さな調査に照らして、私はこれが受け入れられた答えであるべきだと本当に思います:
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
FragmentActivity act = getActivity();
AlertDialog.Builder builder = new AlertDialog.Builder(act);
// ... do your stuff here
Dialog dialog = builder.create();
dialog.setCanceledOnTouchOutside(false);
Window window = dialog.getWindow();
if( window!=null )
{
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
return dialog;
}
つまり、フラグの設定をonCreateDialog()の最後に移動し、setCancelOnTouchOutside(false)を追加します。
受け入れられた答えは、Android 9および10(そしておそらく11)を実行しているSamsung電話では機能しません。それらのシステムでは、samsungは、フラグの設定が非常に早い場合にのみ機能するように変更しました。
上記は、Googleエミュレーター、LG Nexus 5X、HTC Desire 12、Google Pixel 6、いくつかのHuawei電話、およびこれをテストしたすべての(約20)Samsung電話を含むすべての場所で機能します。
ニーズに合わせて適切なスタイルを設定する必要があります。FragmentDialogsのスタイルについて詳しくは、公式ドキュメントをご覧ください。
次のスタイルを使用できると思います。
さて、具体的にしましょう。外部ビューを操作する場合は、ダイアログフラグメントを使用しないでください。代わりに、このようにフラグメントを使用してください。
FragmentTransaction transaction = fragmentManager.beginTransaction();
// For a little polish, specify a transition animation
transaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
// To make it fullscreen, use the 'content' root view as the container
// for the fragment, which is always the root view for the activity
transaction.add(android.R.id.content, newFragment)
.addToBackStack(null).commit();
そして、レイアウトwrap_contentを作成します。これは、明らかにDialogのように見え、デフォルトでは画面の上部に配置されます。
詳細については、こちらをご覧ください
@yanivが答えを提供しました。Runnable
ただし、必要に応じて、同じ結果が得られるが、ルートにを投稿する必要がないスニペットを次に示しますView
。
@NonNull
@Override
public Dialog onCreateDialog(@Nullable final Bundle savedInstanceState) {
final Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
return dialog;
}