I have a custom dialogFragment which basically works, however it only gets dismissed if you click (ie tap) far away from the dialog. If I click very close to the dialog, but still outside (e.g. 30px from the edge), nothing happens... the dialog does not dismiss.
I see this occurs even on a basic alertDialog using no customization. As far as I can tell, this is a standard Android thing. Am I wrong? Is there a reason for it?
There is a property .setCanceledOnTouchOutside(); changing that does affect the working clicking-far-away dismissal as expected, but has no affect on the close-to-the-edge situation described above.
The dialog class:
public class Filters_DialogFragment extends DialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.filters_dialog, container, false);
getDialog().setTitle("Simple Dialog");
// FYI, this has no affect on clicking very close to the dialog edge.
getDialog().setCanceledOnTouchOutside(true);
return rootView;
}
}
The dialog layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#333333">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="FILTERS"
android:textColor="#ffffff" />
<SeekBar
android:id="@+id/seekBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Function in my activity calling the dialog:
private void showFiltersDialog() {
FragmentManager fm = getSupportFragmentManager();
Filters_DialogFragment dialogFragment = new Filters_DialogFragment();
dialogFragment.show(fm, "Sample Fragment");
}
I'd been facing this issue myself, so did some digging through the source code. Turns out it's intentional behaviour, and is called "touchSlop". It's defined in ViewConfiguration:
The offending code is in the Window class:
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
&& isOutOfBounds(context, event) && peekDecorView() != null) {
return true;
}
return false;
}
Which then calls:
private boolean isOutOfBounds(Context context, MotionEvent event) {
final int x = (int) event.getX();
final int y = (int) event.getY();
final int slop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
final View decorView = getDecorView();
return (x < -slop) || (y < -slop)
|| (x > (decorView.getWidth()+slop))
|| (y > (decorView.getHeight()+slop));
}
The value of which comes from:
/**
* Distance in dips a touch needs to be outside of a window's bounds for it to
* count as outside for purposes of dismissing the window.
*/
private static final int WINDOW_TOUCH_SLOP = 16;
I can't find any way to override this behaviour or change the slop value. I think the only option would be to implement a full screen dialog with a transparent background and a manual click handler. I've decided that it's not a good idea for my app to override default system behaviour, so I'm not going to implement it.