I have a Fragment
in my app that shows a DialogFragment
.
I have in the fragment a button that closes the dialog. But when I show the dialogFragment, the touches outside from the dialog do nothing and I can't click the buttons outside from the dialog fragment.
How can I allow outside touches for DialogFragment?
In order to do that, a flag of the Window
that allows the outside touch should be turned on and for the good appearance the background dim flag should be cleared.
Since it must be done after dialog is created, I've implemented it via the 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();
}
});
}
At this moment the outside touch is possible.
In case we want to make it nicer and without the frame, the following code can be added:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Hide title of the dialog
setStyle(STYLE_NO_FRAME, 0);
}
This is more generic flag to allow any action not only touch actions
window.setFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
I have found alternative way to handle dismiss on touch outside. Please check below code sample, that would definitely work,
@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;
}
});
}
In my case, I was getting getDialog() as not null value, but getDialog().dismiss() was not working. Also, the solution that is marked as right above, also did not work in my case. So, I took this approach.
You need to set a proper style for your needs. You can read more about styles for FragmentDialogs in the official docs.
I believe you could use following style:
- STYLE_NO_FRAME
Well, let's be specific. If you want to work with outside views then you should not use dialog fragment, use fragment instead like this.
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();
And make the layout wrap_content, which will apparently looks like Dialog and by default it is placed at the top of the screen.
For more details please visit here
@yaniv has provided the answer. But in case you want, here's a snippet where you get the same result but withou the need to post a Runnable
to the root 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;
}
来源:https://stackoverflow.com/questions/15382540/allow-outside-touch-for-dialogfragment