20

I have searched through all the answers about dismissing a Dialog onTouchOutside, however, I am using DialogFragment in my application. How can I achieve dismissing the DialogFragment when user clicks outside the DialogFragment's region.

I have examined Dialog's source code for setCanceledOnTouchOutside

public void setCanceledOnTouchOutside(boolean cancel) {
    if (cancel && !mCancelable) {
        mCancelable = true;
    }

    mCanceledOnTouchOutside = cancel;
}

There's another function which may be interesting which is isOutOfBounds

private boolean isOutOfBounds(MotionEvent event) {
    final int x = (int) event.getX();
    final int y = (int) event.getY();
    final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
    final View decorView = getWindow().getDecorView();
    return (x < -slop) || (y < -slop)
    || (x > (decorView.getWidth()+slop))
    || (y > (decorView.getHeight()+slop));
}

but I couldn't figure out a way to make use of these for DialogFragment

In addition to these I have examined the state of the application with hierarchyviewer and as I understand it, I can only see the region of the dialog and not the outsied part of it (I mean the remaining part of the screen after the DialogFragment).

Can you suggest a way of implementing this setCanceledOnTouchOutside for DialogFragment and if possible with a sample code?

cesar
  • 8,944
  • 12
  • 46
  • 59
C.d.
  • 9,932
  • 6
  • 41
  • 51

5 Answers5

37

The answer is pretty simple:

MyDialogFragment fragment = new MyDialogFragment(); // init in onCreate() or somewhere else
...
if ( fragment.getDialog() != null )
    fragment.getDialog().setCanceledOnTouchOutside(true); // after fragment has already dialog, i. e. in onCreateView()

See http://developer.android.com/reference/android/app/DialogFragment.html#setShowsDialog%28boolean%29 for more info about dialogs in DialogFragments.

Fenix Voltres
  • 3,448
  • 1
  • 29
  • 36
  • `DialogFragment` does not have a method called `setCanceledOnTouchOutside()` `Dialog` has. Please read the question carefully. – C.d. Feb 14 '12 at 14:49
  • 13
    Above answer does not imply it has. `DialogFragment` has method `getDialog()` which returns `Dialog` which HAS method `setCanceledOnTouchOutside()`. Please read the answer carefully. – Fenix Voltres Feb 14 '12 at 15:05
  • 3
    Oh man.. please be more descriptive.. If you can edit the answer I can upvote it. I have called it inside `onCreateView()` of a custom `DialogFragment` implementation and it works well. Thanks. – C.d. Feb 14 '12 at 15:33
  • I found that I need to add the call to seCanceledOnTouchOutside(true) on Honeycomb but not on ICS. – daveywc Apr 17 '13 at 20:47
  • I would think a better answer would be to have the dialog fragment subclass control whether it should be cancelable. Good places to do so seem to be in onCreateDialog or onCreateView. – Matt Wolfe Apr 21 '16 at 18:12
11

In most cases, getDialog() is null, since you won't get it immediately after you make a new instance of your dialog.

As suggested above onViewCreated is also nor correct for DialogFragment especially when using android.support.v4.app.DialogFragment.

The below works well, as it's placed on the onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    if (getDialog() != null) {
        getDialog().setCanceledOnTouchOutside(true);
    }
    return super.onCreateView(inflater, container, savedInstanceState);
}
ericosg
  • 4,926
  • 4
  • 37
  • 59
  • Override this method in your DialogFragment. That wasn't clear initially as it is commonly overridden in Fragments. – Ivan May 17 '17 at 18:49
  • 1
    @ericosg I am using androidx.fragment.app.DialogFragment and the above answer does not work in my DialogFragment. My test device uses Android 8.0 Oreo and my use case is here: https://stackoverflow.com/questions/59825258/android-how-to-dismiss-a-datepicker-dialogfragment-when-touching-outside. Any thoughts on how to fix? – AJW Jan 22 '20 at 01:00
5

Why not just override onCreateDialog and just set it there. That way you don't have to check for null on the getDialog() call all the time.

 @Override
 public Dialog onCreateDialog(Bundle savedInstanceState) {
     Dialog d =  super.onCreateDialog(savedInstanceState);
     d.setCanceledOnTouchOutside(false);
     return d;
 }
astryk
  • 1,256
  • 13
  • 20
0

I was reading: http://developer.android.com/reference/android/app/DialogFragment.html

It states: "Control of the dialog (deciding when to show, hide, dismiss it) should be done through the API here, not with direct calls on the dialog."

RCB
  • 560
  • 4
  • 9
0

I have answered to another question, but that answer is more appropriate for this problem, My solution . Just to brief here, I simply implemented onTouch() of DialogFragment's getView() and checked touch bounds.

Community
  • 1
  • 1
Swaroop
  • 532
  • 1
  • 4
  • 16