47

I am using the Support library's DrawerLayout in my app. I noticed that, when I click on an empty area in my Drawer view, the underlying View (containing a ListView) receives the Touch event and reacts to it.

The onInterceptTouchEvent method of the DrawerLayout looks like this:

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);

    // "|" used deliberately here; both methods should be invoked.
    final boolean interceptForDrag = mLeftDragger.shouldInterceptTouchEvent(ev) |
            mRightDragger.shouldInterceptTouchEvent(ev);

    boolean interceptForTap = false;

    switch (action) {
        case MotionEvent.ACTION_DOWN: {
            final float x = ev.getX();
            final float y = ev.getY();
            mInitialMotionX = x;
            mInitialMotionY = y;
            if (mScrimOpacity > 0 &&
                    isContentView(mLeftDragger.findTopChildUnder((int) x, (int) y))) {
                interceptForTap = true;
            }
            mDisallowInterceptRequested = false;
            mChildrenCanceledTouch = false;
            break;
        }

        case MotionEvent.ACTION_MOVE: {
            // If we cross the touch slop, don't perform the delayed peek for an edge touch.
            if (mLeftDragger.checkTouchSlop(ViewDragHelper.DIRECTION_ALL)) {
                mLeftCallback.removeCallbacks();
                mRightCallback.removeCallbacks();
            }
            break;
        }

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP: {
            closeDrawers(true);
            mDisallowInterceptRequested = false;
            mChildrenCanceledTouch = false;
        }
    }

    return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
}

My view with the DrawerLayout:

<android.support.v4.widget.DrawerLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/drawer_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <FrameLayout
            android:id="@+id/content"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

    <FrameLayout
            android:id="@+id/sidebar_container"
            android:layout_width="300dp"
            android:layout_height="match_parent"
            android:layout_gravity="left"/>

</android.support.v4.widget.DrawerLayout>

What can I do, (if possible without extending the DrawerLayout class) to prevent this behaviour? As long as the drawer is open, I want no click events to reach the background view.

janoliver
  • 7,744
  • 14
  • 60
  • 103
  • When the drawer is about to be opened add a simple `View` on top of your app's current content which has a `OnTouchListener` set on it to return `true`(meaning it will eat all the touch events). – user Sep 15 '13 at 11:55
  • 1
    This seems rather hacky, but is a simple solution. I hoped for an API method, though... – janoliver Sep 15 '13 at 12:11
  • @janoliver did you come up with a more elegant solution? – ataulm Oct 17 '13 at 09:44

1 Answers1

85

Set clickable to true on the drawer - it'll consume the touch.

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <FrameLayout
        android:id="@+id/content_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <FrameLayout
        android:id="@+id/drawer_view"
        android:layout_width="300dp"
        android:clickable="true"
        android:importantForAccessibility="no"
        android:layout_height="match_parent"
        android:layout_gravity="left"/>

</android.support.v4.widget.DrawerLayout>

I added android:importantForAccessibility="no" because marking the drawer as interactive (clickable or focusable) will make the entire drawer visible to accessibility services like TalkBack.

This is not what you want (usually) - more often, items inside the drawer should be accessible to the services.

This attribute is only available on API 16+.

ataulm
  • 15,195
  • 7
  • 50
  • 92
  • 1
    Sounds reasonable. I will try it later, thank you for the answer! And to answer your comment-question: I did not find an elegant solution yet. Your's would be the first. :) – janoliver Oct 17 '13 at 11:11
  • 8
    I just wanted to add a note for anyone that might find it helpful. My `DrawerLayout` contained a `fragment` instead of `FrameLayout` for `@+id/sidebar_container` (or `@+id/navigation_drawer` in my case). You can simply add `android:clickable="true"` to the base Layout of that fragment's xml file instead because `fragment` won't recognize the `clickable` attribute. – Mike Cole Dec 29 '14 at 22:50
  • A great solution! – syed muhammad awais Oct 05 '21 at 19:05