禁用 DrawerLayout 的稀松布触摸手势

Disable DrawerLayout's scrim touch gesture

我需要禁用稀松布上的触摸手势(红色突出显示的部分)。我只想滑动关闭抽屉。

问题是,当抽屉布局打开时,我需要 select 红色突出显示部分下方的 ListView 中的一个元素,发生的事情是抽屉关闭,只有在这一点上我才能select ListView 中的一个元素。

我需要 select 直接从 ListView 获取元素,打开抽屉时也是如此

我在这里问了一个问题:

正在触发 parent (drawer) ontouchevent,而不是 childlistview.

我在这里也回答过类似的问题:

您需要管理您的触摸事件,以便由 child 处理。您需要使用 onInterceptTouchEvent 和 return false。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    // returning false means the child will handle the touch event.
    return false;
}

然后你管理你touchevent的列表视图:

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // This method will only be called if the touch event was intercepted in 
    // onInterceptTouchEvent
    // TODO Select your listview item.

}

您还可以确定正在发生的触摸事件类型,例如滚动并确定 child 或 parent 是否将管理该事件。

Managing Touch Events in a ViewGroup

我从这里添加了这句话 Understanding Android Input Touch Events System Framework (dispatchTouchEvent, onInterceptTouchEvent, onTouchEvent, OnTouchListener.onTouch):

The root view starts dispatching the event down to its children. Let’s presume that we have this hierarchy:

A – ViewGroup1 (parent of B).
B – ViewGroup2 (parent of C).
C – View (child of B)
– receives a touch/tap/click. Now the root view will call A.dispatchTouchEvent(). Now the job of a ViewGroup.dispatchEvent() (not View.dispatchEvent()) is to find out all the child views and view groups whose bounds contain the touch point coordinates (using a hit testing algorithm). When it figures out a list of relevant children, it starts dispatching the events to them by calling their dispatchTouchEvent().

Here’s an important piece though. Before the dispatchTouchEvent() is called on the children, the A.dispatchTouchEvent() will first call A.onInterceptTouchEvent() to see if the view group is interested in intercepting the event and handling the subsequent gesture by itself (scrolling is a good use case where a fling on B should lead to scrolling on A). The method onInterceptTouchEvent() is only available on view groups (as they’re the one who can be parents/containers with the requirement to intercept touch events) that can sort of keep an eye on the event and hijack it by returning true. If it returns false then dispatching continues as usual, i.e., B.dispatchTouchEvent() (child) will be called. But on returning true, this is what’ll happen:

ACTION_CANCEL will be dispatched to all the children.
All the subsequent gesture events (till ACTION_UP/ACTION_CANCEL) will be consumed by the event listeners (OnTouchListener.onTouch()) if defined, else the event handler A.onTouchEvent() at A’s level.
A.onInterceptTouchEvent() itself will be never called again.

With this diagram:

如果您需要更多解释,请告诉我。

你必须像这样创建自定义抽屉

public class CustomDrawer extends DrawerLayout {



    public CustomDrawer(Context context) {
        super(context);

    }

    public CustomDrawer(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

    }

    public CustomDrawer(Context context, AttributeSet attrs) {
        super(context, attrs);

    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if(isDrawerOpen(Gravity.START)){
            if(event.getX() > getChildAt(1).getWidth()){
                return false;
            }
        }
        return super.onInterceptTouchEvent(event);
    }

}

注意:getChildAt(1)应该是child你给的"start"引力,它的宽度决定了打开抽屉的宽度。

希望这能解决您的问题

只需将 android:clickable="true" 添加到抽屉菜单。