Android 開源SlidingMenu的bug修改,androidslidingmenu
SlidingMenu相信大家都已經很熟悉了 ,原始碼託管在 https://github.com/jfeinstein10/SlidingMenu。首先我要感謝下原作者的大無畏精神,因為開源而偉大,哈哈。如果我們的項目中只想用到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。原始碼還是很多的,想要全部弄清楚還是要花時間滴,只能先針對現象解決問題啦。
現在android要做側滑功能表列用SlidingMenu開源項目好,還是用android內建的Navigation Drawer好?
如果是學習代碼的話,建議還是學習官方的,不過SlidingMenu有很多功能,比如滑出菜單時控制後面的背景動不動,動多少,貌似Navigation Drawer的背景不能動的。開源項目被官方API取代是趨勢,因為大家都覺得官方的介面用著放心嘛,但開源項目可能更靈活。
錯誤提示