Two soluctions.
- setting
android:clickable
- copy the source code of drawerlayout and delete peekDrawer function to disabled this feature
Let me explain why the reason of this bug.
DrawerLayout three states
STATE_IDLE, STATE_DRAGGING, STATE_SETTLING
ACTION_DOWN-> onEdgeTouched will be triggered if it is on the edge, DrawerLayout will trigger peekDrawer after 120ms
PeekDrawer actually changes the state of DrawerLayout to STATE_SETTLING, and then lets the Drawer scroll to the specified location. Then set the state to IDLE.
ACTION_MOVE->
If the current state is DRAGGING, drag captureView
If the current state is not DRAGGING, it will try to execute tryCaptureViewForDrag to reset the state to DRAGGING.
And at the same time, it will also determine whether a new edge gesture is triggered (emphasis !!)
If a new edge gesture was dete, it will invoke onEdgeDragStared
and DrawerLayout will go to captureView to captrue the drawer
How the recuurent this bug?
- First tap the edge to invoke a 120ms delay function
peekDrawer
- Before the peekDrawer was invoked, trigger onEdgeDragStared let the drawer layout capture the drawer, the dragState will be seted to STATE_DRAGGING
- After 120ms, If your finger are still in the area that drawerLayout want to peek to , the dragState will be set to SETTLING
- Before the drawer peek to the destination, move your finger fast out of that area before the peek end, the drawer will not follow your finger because the state is SETTLING, after SETTLING the state will be set to IDLE
- Now your finger is totally out of the drawer and the state is IDLE , so you can’t drag the view anymore
So, the solution is to stop the peekDrawer
actually, the drawerlayout has fixed this problem.
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (action) {
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;
}
}
return interceptForDrag || interceptForTap || hasPeekingDrawer() || mChildrenCanceledTouch;
}
If the child is clickable, the child will consume the event, the onInterceptTouchEvent will invoke many times. and remove the peekDraw while move.