SlidingMenu源碼解析

SlidingMenu

主要用來提供應(yīng)用中側(cè)滑導(dǎo)航欄迟蜜,提供左右滑動的效果,可配置性很高荡短,很多知名應(yīng)用也在使用丐枉,例如大家比較熟悉的LinkedIn,SlidingMenu主要由以下三部分構(gòu)成

SlidingMenu.java

提供公有api給用戶掘托,做一些基本的屬性配置修改

attachToActivity(Activity activity, int slideStyle, boolean actionbarOverlay)
  • slideStyle 有兩種模式 SLIDING_WINDOW(滑動整個界面.包含actionbar); SLIDING_CONTENT(不包含actionbar)
  • actionbarOverlay 是控制控件是否給頂部 status bar 預(yù)留空間
setContent(int res or View view) 
getContent()
  • 設(shè)置主視圖瘦锹,可忽略此方法,在調(diào)用 attacthToActivity 后會將當前activity contentview 加入其中
setMenu(int res or View view)
getMenu()
  • 設(shè)置左側(cè)滑動視圖
setSecondaryMenu(int res or View view)
getSecondaryMenu()
  • 設(shè)置 右側(cè)滑動視圖
setSlidingEnabled(boolean b)
isSlidingEnabled()
  • 設(shè)置是否可滑動
setMode(int mode)
getMode()
  • 設(shè)置滑動類型,僅可使用LEFT(0)闪盔,RIGHT(1)弯院,LEFT_RIGHT(2) 對應(yīng)僅左滑,僅右滑泪掀,左右均可滑動听绳。
setStatic(boolean b)
  • 我理解正如其命名,設(shè)置為true的話這個控件將完全失效异赫,將等同于一個普通的viewgroup, 與setSlidingEnabled類似椅挣。
showMenu()
showMenu(boolean animate)
isMenuShowing()

showSecondaryMenu()
showSecondaryMenu(boolean animate)
isSecondaryMenuShowing()

showContent()
showContent(boolean animate)

toggle()
toggle(boolean animate)

  • 以上控制左側(cè),右側(cè)塔拳,和內(nèi)容區(qū)的顯隱鼠证,toggle只控制左側(cè)和內(nèi)容區(qū)的切換。
getBehindOffset()
setBehindOffset(int i) //側(cè)邊滑動后相對于屏幕邊界的距離
setBehindOffset(int resID)

setBehindWidth(int i)    //側(cè)邊欄寬度
setBehindWidthRes(int res)

setAboveOffset(int i)
setAboveOffsetRes(int resID)

  • 歸根到底主要是為了設(shè)置側(cè)邊欄的寬度
setBehindScrollScale(float f)
getBehindScrollScale()
  • f 取值 0-1 主要為了在滑動時形成視差滾動靠抑,1f 將沒有視差效果
setFadeEnabled(boolean b)
setFadeDegree(float f)
  • f 取值 0-1 主要為了在滑動完成一個側(cè)邊view透明度漸變的過程
setTouchModeBehind(int i)
setTouchModeAbove(int i)

//TouchMode為TOUCHMODE_MARGIN時調(diào)用以下方法改變邊界響應(yīng)寬度
setTouchmodeMarginThreshold(int touchmodeMarginThreshold)
getTouchmodeMarginThreshold()
  • 設(shè)置主視圖和側(cè)邊欄滑動響應(yīng)模式 僅支持這三種模式TOUCHMODE_FULLSCREEN(全屏響應(yīng))TOUCHMODE_MARGIN(邊界響應(yīng)) TOUCHMODE_NONE(不響應(yīng))
setShadowDrawable(int resId)
setShadowDrawable(Drawable d)
setSecondaryShadowDrawable(int resId)
setSecondaryShadowDrawable(Drawable d)
setShadowWidthRes(int resId)
setShadowWidth(int pixels)
  • 設(shè)置陰影以及陰影寬度
addIgnoredView(View v)
removeIgnoredView(View v)
clearIgnoredViews()
  • 添加忽略視圖量九,內(nèi)層可能包含一些自己的可滑動view會引起一些滑動沖突,在不需要此touch事件時 及時 removeIgnoredView
setOnOpenListener(OnOpenListener listener)
setSecondaryOnOpenListner(OnOpenListener listener)
setOnCloseListener(OnCloseListener listener)
setOnOpenedListener(OnOpenedListener listener)
setOnClosedListener(OnClosedListener listener)
  • 一些menu打開和關(guān)閉的回調(diào)颂碧,onOpen和onClose都不會在打開和關(guān)閉的第一時間調(diào)用荠列,使用時要注意
setBehindCanvasTransformer(CanvasTransformer t)
  • 將會返回側(cè)邊欄的畫布和打開的百分比,通過這些參數(shù)可以對側(cè)邊欄view做一些動畫處理稚伍,如伸縮放弯予,漸變等,slidingmenu提供了一些基礎(chǔ)效果个曙,也可以自己實現(xiàn)锈嫩。

CustomViewAbove.java

主要處理界面的touch事件受楼,解決滑動沖突,控制著整個控件當前的滑動狀態(tài)呼寸,大部分方法屬性也傳遞到slidingmenu.java暴露給了用戶艳汽。

CustomViewBehind.java

主要處理界面的一些基本屬性及狀態(tài),如滑動時視差滾動对雪,透明度漸變河狐,對畫布的操作,陰影的繪制等瑟捣,大部分方法也通過slidingmenu.java暴露給了用戶馋艺,Behind View 中的touch事件也延用了Above View 的touch 事件,相當于統(tǒng)一交予Above View來處理

FAQ

1.當設(shè)置setTouchModeBehind(SlidingMenu.TOUCHMODE_FULLSCREEN)后迈套,側(cè)邊欄中的內(nèi)容的click事件都失效了(issues446)

修改CustomViewAbove.javaonInterceptTouchEvent()ACTION_DOWN事件 如下

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;
    }
    return mQuickReturn;

修改CustomViewAbove.javaonInterceptTouchEvent()onTouchEvent事件 如下

case MotionEvent.ACTION_DOWN:
    /*
     * If being flinged and user touches, stop the fling. isFinished
     * will be false if being flinged.
     */
    completeScroll();

    // Remember where the motion event started
    int index = MotionEventCompat.getActionIndex(ev);
    mActivePointerId = MotionEventCompat.getPointerId(ev, index);
    mLastMotionX = mInitialMotionX = ev.getX();
    return mQuickReturn;

CustomViewAbove.javainitCustomViewAbove()中移除setInternalPageChangeListener方法
修改CustomViewBehind.javaonInterceptTouchEvent onTouchEvent 方法如下

 @Override
 public boolean onInterceptTouchEvent(MotionEvent e) {
     return mViewAbove.onInterceptTouchEvent(e);
 }

 @Override
 public boolean onTouchEvent(MotionEvent e) {
     return mViewAbove.onTouchEvent(e);
 } 
2.如何實現(xiàn)類似QQ5.0 ResideMen這樣的側(cè)滑效果

一種通過是通過setBehindCanvasTransformer這個方法獲取打開的百分比來完成動畫效果捐祠,如下偽代碼


//以下縮放比例和執(zhí)行動畫的視圖均更具自己情況定義
//percentOpen 0-1
menu.setBehindCanvasTransformer(new CanvasTransformer() {
   
   @Override
   public void transformCanvas(Canvas canvas, float percentOpen) {
      ViewHelper.setScaleX(contentView, percentOpen);
      ViewHelper.setScaleY(contentView, percentOpen);
   }
  }); 

此方法雖然大致可以滿足,但percentOpen是經(jīng)過多次計算所得桑李,可能和我們需要的值有一定誤差踱蛀,會造成動畫的抖動。

另一種需要對原項目進行一些改造贵白,在CustomViewAbove.java中定義接口來拿到精確值 率拒,偽代碼如下

//定義接口
public interface OnSlidingListener{
    public void onSliding(float x);
}

//訂閱事件
public void setOnSlidingListener(OnSlidingListener l){
  mSlidingListener = l;
}

//回調(diào)數(shù)據(jù)
@Override
 public void scrollTo(int x, int y) {
  mSlidingListener.onMenuSliding(Math.abs(x));
  super.scrollTo(x, y);
  mScrollX = x;
  mViewBehind.scrollBehindTo(mContent, x, y); 
  ((SlidingMenu)getParent()).manageLayers(getPercentOpen());
 }

然后在SlidingMenu.java 訂閱事件,將api暴露給用戶即可禁荒,那道當前滑動的value x 經(jīng)過換算成我們需要的值猬膨,執(zhí)行動畫即可。

3.如何使slidingmenu上下左右都可以滑動呢圈浇?

我們可以下載all-sides分支上的代碼

4.滑動過程使主視圖透明度漸變而不是側(cè)邊欄

可查看這里
也可以在自己的代碼中進行控制寥掐,因為我們可以得到滑動距離(上面2中所說),滑動百分比這些值磷蜀,所以通過這些值來操作view 的漸變召耘,位移等就輕而易舉了

5.當我點擊屏幕沒有松開,又點擊了back鍵或home鍵褐隆,再次進入后無法滑動了

這里需要對代碼進行些調(diào)整 修改 CustomViewAbove.java 中的 onTouchEvent 偽代碼如下


@Override
 public boolean onTouchEvent(MotionEvent ev) {

  if (!mEnabled)
   return false;
  //這里有修改  add !mQuickReturn
  if (!mIsBeingDragged && !mQuickReturn &&!thisTouchAllowed(ev))
   return false;

  //  if (!mIsBeingDragged && !mQuickReturn)
  //   return false;

  final int action = ev.getAction();

  if (mVelocityTracker == null) {
   mVelocityTracker = VelocityTracker.obtain();
  }
  mVelocityTracker.addMovement(ev);

  switch (action & MotionEventCompat.ACTION_MASK) {
  case MotionEvent.ACTION_DOWN:
  .
  .
  .
   } else { 
     setCurrentItemInternal(mCurItem, true, true, initialVelocity);
    }
    mActivePointerId = INVALID_POINTER;
    //endDrag();  這里刪除
   } else if (mQuickReturn && mViewBehind.menuTouchInQuickReturn(mContent, mCurItem, ev.getX() + mScrollX)) {  
    setCurrentItem(1);
    //endDrag(); 這里刪除
   }
    endDrag();   //這里添加
   break;
  case MotionEvent.ACTION_CANCEL:
   if (mIsBeingDragged) {
    setCurrentItemInternal(mCurItem, true, true);
    mActivePointerId = INVALID_POINTER;
    //endDrag();  這里刪除
   }
  // 這里添加
   break;
  case MotionEventCompat.ACTION_POINTER_DOWN: {

BTW

  • 此項目最好不要通過add jar方式加入污它,以便日后的擴展,我們需要的可能僅僅是上面提到的3個類

  • 最好是繼承原項目提供的SlidingxxxActivity.java 或則使用原項目提供的SlidingActivityHelper.java

  • 最好不要在滑動過程中去請求網(wǎng)絡(luò)來更新界面庶弃,如此項目中 你打開后然后立馬關(guān)上 如果你在onOpend去請求網(wǎng)絡(luò)衫贬,然后關(guān)上的過程中接受到請求數(shù)據(jù)需要更新ui 這樣將會造成動畫的卡頓,有時可能很難察覺歇攻,但確實影響了體驗固惯,需要自己去控制。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缴守,一起剝皮案震驚了整個濱河市葬毫,隨后出現(xiàn)的幾起案子镇辉,更是在濱河造成了極大的恐慌,老刑警劉巖贴捡,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忽肛,死亡現(xiàn)場離奇詭異,居然都是意外死亡烂斋,警方通過查閱死者的電腦和手機屹逛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來汛骂,“玉大人罕模,你說我怎么就攤上這事×辈t!?“怎么了手销?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長图张。 經(jīng)常有香客問我,道長诈悍,這世上最難降的妖魔是什么祸轮? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮侥钳,結(jié)果婚禮上适袜,老公的妹妹穿的比我還像新娘。我一直安慰自己舷夺,他們只是感情好苦酱,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著给猾,像睡著了一般疫萤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上敢伸,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天扯饶,我揣著相機與錄音,去河邊找鬼池颈。 笑死尾序,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的躯砰。 我是一名探鬼主播每币,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼琢歇!你這毒婦竟也來了兰怠?” 一聲冷哼從身側(cè)響起梦鉴,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎痕慢,沒想到半個月后尚揣,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡掖举,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年快骗,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片塔次。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡方篮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出励负,到底是詐尸還是另有隱情藕溅,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布继榆,位于F島的核電站巾表,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏略吨。R本人自食惡果不足惜集币,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望翠忠。 院中可真熱鬧鞠苟,春花似錦、人聲如沸秽之。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽考榨。三九已至跨细,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間河质,已是汗流浹背扼鞋。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留愤诱,地道東北人云头。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像淫半,于是被迫代替她去往敵國和親溃槐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容