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.java
中onInterceptTouchEvent()
中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.java
中onInterceptTouchEvent()
中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.java
中initCustomViewAbove()
中移除setInternalPageChangeListener
方法
修改CustomViewBehind.java
中 onInterceptTouchEvent
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 這樣將會造成動畫的卡頓,有時可能很難察覺歇攻,但確實影響了體驗固惯,需要自己去控制。