Kalnode
Kalnode

Reputation: 11394

dialogFragment doesn't dismiss when clicking close to it's edge

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?

enter image description here

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");

}

Upvotes: 2

Views: 1412

Answers (1)

Darren Taft
Darren Taft

Reputation: 198

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:

https://developer.android.com/reference/android/view/ViewConfiguration.html#getScaledWindowTouchSlop()

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.

Upvotes: 4

Related Questions