SlidingMenu相信大家都已经很熟悉了 ,源代码托管在 https://github.com/jfeinstein10/SlidingMenu。首先我要感谢下原作者的大无畏精神,因为开源而伟大,哈哈。如果我们的项目中只想用到SlidingMenu,那我们就要把SlidingMenu这个控件给抽离出来了。这个是我抽离出来的的SlidingMenu控件源代码(大家有需要的可以下载学习下)。如下:
我也很自豪的将这个开源控件运用在自己公司的项目中了,可是经公司的测试人员测试后,发现一个问题,SlidingMenu来回的快速切换(当SlidingMenu打开时,一个手指点击SlidingMenu的下方布局(代码中:自定义的CustomViewBehind),另一个手指同时点击SlidingMenu的上方布局(CustomViewAbove)),频繁的如此操作会出现这个一个现象(不是必现的哦):当SlidingMenu关闭后,任凭我怎么点击布局上面的控件,事件都不响应了,起初以为是应用卡死了,可是按设备上的退出,应用可以正常退出。那我初步定位原因就是CustomViewAbove这个自定义的ViewGroup把手势事件给拦截了,以致于子View接受不到事件,就响应不了了。
那我们可以直接去看SlidingMenu控件的源代码了,找到CustomViewAbove.java,然后我们找到这个方法onInterceptTouchEvent(),这个方法是ViewGroup的一个方法,目的是在系统向该ViewGroup及其各个childView触发onTouchEvent()之前对相关事件进行一次拦截.如果onInterceptTouchEvent返回true,就表示该ViewGroup不会将事件向它的子childView传递了;返回false,就不拦截事件了。因此我觉得CustomViewAbove.java中的在上面那个现象中onInterceptTouchEvent方法返回true了,所以各种手势事件都不响应了。我们看代码吧:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (!mEnabled)
return false;
final int action = ev.getAction() & MotionEventCompat.ACTION_MASK;
if (DEBUG)
if (action == MotionEvent.ACTION_DOWN)
Log.v(TAG, "Received ACTION_DOWN");
if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP
|| (action != MotionEvent.ACTION_DOWN && mIsUnableToDrag)) {
endDrag();
return false;
}
switch (action) {
case MotionEvent.ACTION_MOVE:
determineDrag(ev);
break;
case MotionEvent.ACTION_DOWN:
int index = MotionEventCompat.getActionIndex(ev);
mActivePointerId = MotionEventCompat.getPointerId(ev, index);
if (mActivePointerId == INVALID_POINTER)
break;
mLastMotionX = mInitialMotionX = MotionEventCompat.getX(ev, index);
mLastMotionY = MotionEventCompat.getY(ev, index);
if (thisTouchAllowed(ev)) {
mIsBeingDragged = false;
mIsUnableToDrag = false;
if (isMenuOpen() && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {
mQuickReturn = true;
}
} else {
mIsUnableToDrag = true;
}
break;
case MotionEventCompat.ACTION_POINTER_UP:
onSecondaryPointerUp(ev);
break;
}
if (!mIsBeingDragged) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(ev);
}
return mIsBeingDragged || mQuickReturn;
}
看源代码发现,onInterceptTouchEvent返回true或者false是由mIsBeingDragged(是否正在拖拽) 和 mQuickReturn(是否快速返回)两个成员变量决定的。因此在某个特殊场景下,合理状况是当SlidngMenu已经
关闭了,那IsBeingDragged和 mQuickReturn应该同时为false,但上述那个现象的原因就是IsBeingDragged或者mQuickReturn为true。说明频繁的非常规操作,我们没处理好这两个变量。看源代码,我发现每次ACTION_DOWN
时应该置IsBeingDragged和 mQuickReturn为false,因为ACTION_DOWN事件发生时,不可能正在拖拽或者SlidingMenu
快速关闭。见我添加的这两行代码(如下):
case
MotionEvent.ACTION_DOWN:
mIsBeingDragged = false;
mQuickReturn = false;
OK,这个BUG就这样解决了,说明在每次SlidingMenu关闭后IsBeingDragged和 mQuickReturn的值有问题,所以我决定在每次ACTION_DOWN将这两个变量都置false。源代码还是很多的,想要全部弄清楚还是要花时间滴,只能先针对现象解决问题啦。