Android自定義View之仿QQ側(cè)滑菜單實現(xiàn)

最近蠢棱,由于正在做的一個應(yīng)用中要用到側(cè)滑菜單甩栈,所以通過查資料看視頻,學(xué)習(xí)了一下自定義View量没,實現(xiàn)一個類似于QQ的側(cè)滑菜單,順便還將其封裝為自定義組件殴蹄,可以實現(xiàn)類似QQ的側(cè)滑菜單和抽屜式側(cè)滑菜單兩種菜單。

下面先放上效果圖:

側(cè)滑菜單

抽屜式側(cè)滑

我們這里的側(cè)滑菜單主要是利用HorizontalScrollView來實現(xiàn)的刺下,基本的思路是,一個布局中左邊是菜單布局怠李,右邊是內(nèi)容布局蛤克,默認(rèn)情況下,菜單布局隱藏构挤,內(nèi)容布局顯示,當(dāng)我們向右側(cè)滑筋现,就會將菜單拉出來,而將內(nèi)容布局的一部分隱藏矾飞,如下圖所示:

這里寫圖片描述

下面我們就一步步開始實現(xiàn)一個側(cè)滑菜單呀邢。

一、定義一個類SlidingMenu繼承自HorizontalScrollView

我們后面所有的邏輯都會在這個類里面來寫价淌,我們先寫上其構(gòu)造方法

public class SlidingMenu extends HorizontalScrollView {
    /**
     * 在代碼中使用new時會調(diào)用此方法
     * @param context
     */
    public SlidingMenu(Context context) {
        this(context, null);
    }

    /**
     * 未使用自定義屬性時默認(rèn)調(diào)用
     * @param context
     * @param attrs
     */
    public SlidingMenu(Context context, AttributeSet attrs) {
        //調(diào)用三個參數(shù)的構(gòu)造方法
        this(context, attrs, 0);

    }

    /**
     * 當(dāng)使用了自定義屬性時會調(diào)用此方法
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

二瞒津、定義菜單布局文件

left_menu.xml文件代碼如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:orientation="vertical">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawablePadding="20dp"
            android:layout_marginLeft="20dp"
            android:gravity="left|center"
            android:drawableLeft="@mipmap/ic_launcher"
            android:text="第一個Item"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawablePadding="20dp"
            android:layout_marginLeft="20dp"
            android:gravity="left|center"
            android:drawableLeft="@mipmap/ic_launcher"
            android:text="第二個Item"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawablePadding="20dp"
            android:layout_marginLeft="20dp"
            android:gravity="left|center"
            android:drawableLeft="@mipmap/ic_launcher"
            android:text="第三個Item"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawablePadding="20dp"
            android:layout_marginLeft="20dp"
            android:gravity="left|center"
            android:drawableLeft="@mipmap/ic_launcher"
            android:text="第四個Item"/>
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:drawablePadding="20dp"
            android:layout_marginLeft="20dp"
            android:gravity="left|center"
            android:drawableLeft="@mipmap/ic_launcher"
            android:text="第五個Item"/>
    </LinearLayout>
</RelativeLayout>

上面其實就是定義了一列TextView來模仿菜單的Item項

三巷蚪、定義主布局文件,使用自定義的View

activity_main.xml文件代碼如下

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <!--自定義View-->
   <com.codekong.qq_50_slidingmenu.view.SlidingMenu
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:rightPadding="100dp"
       app:drawerType="false"
       android:scrollbars="none">
       <LinearLayout
           android:layout_width="wrap_content"
           android:layout_height="match_parent"
           android:orientation="horizontal">
            <!--引入菜單布局-->
           <include layout="@layout/left_menu"/>
            <!--內(nèi)容布局-->
           <LinearLayout
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:background="@drawable/qq_bg">

           </LinearLayout>
       </LinearLayout>
   </com.codekong.qq_50_slidingmenu.view.SlidingMenu>
</RelativeLayout>

四屁柏、自定義成員變量

我們定義一些成員變量以便于后面使用

//自定義View布局中內(nèi)嵌的第一層的LinearLayout
private LinearLayout mWapper;
//菜單布局
private ViewGroup mMenu;
//內(nèi)容布局
private ViewGroup mContent;
//屏幕寬度
private int mScreenWidth;
//菜單距屏幕右側(cè)的距離,單位dp
private int mMenuRightPadding = 50;
//菜單的寬度
private int mMenuWidth;
//定義標(biāo)志,保證onMeasure只執(zhí)行一次
private boolean once = false;
//菜單是否是打開狀態(tài)
private boolean isOpen = false;

五肴焊、拿到屏幕寬度的像素值

因為目前為止,我們沒有使用自定義屬性娶眷,所以自定義View默認(rèn)會調(diào)用兩個參數(shù)的構(gòu)造方法,但因為我們第一步中寫構(gòu)造方法時是在兩個參數(shù)的構(gòu)造方法中調(diào)用了三個參數(shù)的構(gòu)造方法届宠,所以,我們將獲取屏幕寬度的代碼寫在三個參數(shù)的構(gòu)造方法中豌注,后面我們自定義屬性后獲取屬性值也是在三個參數(shù)的構(gòu)造方法中書寫相應(yīng)的邏輯。

/**
 * 當(dāng)使用了自定義屬性時會調(diào)用此方法
 * @param context
 * @param attrs
 * @param defStyleAttr
 */
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    //通過以下步驟拿到屏幕寬度的像素值
    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
    DisplayMetrics displayMetrics = new DisplayMetrics();
    windowManager.getDefaultDisplay().getMetrics(displayMetrics);
    mScreenWidth = displayMetrics.widthPixels;
}

六轧铁、實現(xiàn)onMeasure()方法

onMeasure()方法是自定義View的正式第一步,它用來決定內(nèi)部View(子View)的寬和高齿风,以及自身的寬和高,下面是具體的代碼邏輯救斑。

/**
* 設(shè)置子View的寬和高
* 設(shè)置自身的寬和高
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   if (!once){
       once = true;
       mWapper = (LinearLayout) getChildAt(0);
       mMenu = (ViewGroup) mWapper.getChildAt(0);
       mContent = (ViewGroup) mWapper.getChildAt(1);
       //菜單和內(nèi)容區(qū)域的高度都可以保持默認(rèn)match_parent
       //菜單寬度 = 屏幕寬度 - 菜單距屏幕右側(cè)的間距
       mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
       mContent.getLayoutParams().width = mScreenWidth;
       //當(dāng)設(shè)置了其中的菜單的寬高和內(nèi)容區(qū)域的寬高之后,最外層的LinearLayout的mWapper就自動設(shè)置好了
   }
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

七、實現(xiàn)onLayout()方法

onLayout()方法中主要是確定自定義View中子View放置的位置穷娱。下面是具體的代碼。

/**
 * 通過設(shè)置偏移量將Menu隱藏
 * @param changed
 * @param l
 * @param t
 * @param r
 * @param b
 */
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {

    super.onLayout(changed, l, t, r, b);
    if (changed){
        //布局發(fā)生變化時調(diào)用(水平滾動條向右移動menu的寬度,則正好將menu隱藏)
        this.scrollTo(mMenuWidth, 0);
    }
}

這個比較好理解泵额,由于我們使用的是水平滾動布局,我們默認(rèn)情況下相當(dāng)于將水平滾動條向右拖動菜單寬度的的距離嫁盲,這樣左邊布局的菜單就正好被隱藏了。

八亡资、onTouchEvent()方法

該方法主要處理內(nèi)部內(nèi)部View的移動澜共,我們可以在其中寫一些邏輯控制自定義View內(nèi)部的滑動事件嗦董。
由于我們的自定義View是繼承自HorizontalScrollView,我們不再處理按下和移動事件瘦黑,保持HorizontalScrollView默認(rèn)的即可,但對于手指抬起事件幸斥,我們需要根據(jù)手指在水平X軸方向的位移來做出打開菜單或關(guān)閉菜單的操作,所以我們的邏輯代碼如下:

@Override
public boolean onTouchEvent(MotionEvent ev) {
    int action = ev.getAction();
    //按下和移動使用HorizontalScrollView的默認(rèn)處理
    switch (action){
        case MotionEvent.ACTION_UP:
            //隱藏在左邊的位置
            int scrollX = getScrollX();
            if (scrollX > mMenuWidth / 2){
                //隱藏的部分較大, 平滑滾動不顯示菜單
                this.smoothScrollTo(mMenuWidth, 0);
                isOpen = false;
            }else{
                //完全顯示菜單
                this.smoothScrollTo(0, 0);
                isOpen = true;
            }
            return true;
    }
    return super.onTouchEvent(ev);
}

上面最難理解的的就是getScrollX()廊勃,它指的是菜單隱藏未顯示的那部分的寬度。關(guān)于詳細(xì)的解釋坡垫,大家可以去看源碼,也可以去看看這篇博客 圖解Android View的scrollTo(),scrollBy(),getScrollX(), getScrollY()冰悠,講的很清楚。

其實到這一步為止溉卓,一個基本的側(cè)滑菜單已經(jīng)做出來了,下面我們將使用屬性動畫對我們的自定義View進(jìn)行擴(kuò)展搬泥,使其實現(xiàn)最開始展示的抽屜式側(cè)滑菜單。

九佑钾、屬性動畫實現(xiàn)抽屜式側(cè)滑

接下來我們實現(xiàn)抽屜式側(cè)滑烦粒,抽屜式側(cè)滑說白了就是,我們的菜單不是一點點被拉出來扰她,而是看起來菜單就藏在頁面的背后,隨著我們向右滑動徒役,一點點顯露出來。
實現(xiàn)的思路很簡單忧勿,當(dāng)我們拖動時瞻讽,我們讓菜單布局的偏移量等于getScrollX()的值,也就是時刻把菜單隱藏在左邊的部分向右偏移出來速勇,這樣我們看起來就像菜單藏在頁面后面。如下圖:

這里寫圖片描述

當(dāng)我們左右滑動時會觸發(fā)onScrollChanged()方法烦磁,我們在此處算出菜單需要的實時的偏移量,然后調(diào)用屬性動畫即可都伪。
下面說說具體實現(xiàn)代碼:

/**
 * 滾動發(fā)生時調(diào)用
 * @param l  getScrollX()
 * @param t
 * @param oldl
 * @param oldt
 */
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    float scale = l * 1.0f / mMenuWidth;  //1 ~ 0
    //調(diào)用屬性動畫,設(shè)TranslationX
    mMenu.setTranslationX(mMenuWidth * scale);
}

上面方法中的 l 就是上一步中提到的getScrollX()獲得的值。當(dāng)我們沒有拉菜單時陨晶,菜單需要的偏移量就是整個菜單的寬度,當(dāng)我們將菜單完全拉出時珍逸,菜單就不需要偏移量了,此時偏移量為0谆膳。此時我們的抽屜式側(cè)滑就做好了。

注:此處的屬性動畫是在Android3.0之后引入的漱病,如果需要兼容更早的版本,可以用相關(guān)的兼容庫把曼。

十、自定義屬性實現(xiàn)靈活配置

自定義屬性主要是方便使用者可以根據(jù)具體的場景實現(xiàn)不同的效果嗤军。比如,我們可以通過在xml文件中配置叙赚,實現(xiàn)菜單是普通的側(cè)滑式還是抽屜式。在剛開始震叮,我們在自定義View中將菜單打開時,菜單右邊緣距離屏幕右邊緣的值設(shè)置為50dp苇瓣,我們通過自定義屬性可以實現(xiàn)在xml文件中自己配置合適的值。

自定義屬性按下面的步驟進(jìn)行:

1 . 在 res/values 目錄下新建attr.xml文件,文件中寫入的內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
   <attr name="rightPadding" format="dimension"/>
   <attr name="drawerType" format="boolean"/>
   <declare-styleable name="SlidingMenu">
       <attr name="rightPadding"/>
       <attr name="drawerType"/>
   </declare-styleable>
</resources>

上面的比較好理解贪薪,我們先在上面聲明兩個自定義的屬性的名稱及其對應(yīng)的類型,然后再在下面的具體的自定義樣式中引用它們古掏。上面兩個自定義的屬性分別是菜單拉開時右邊緣距離屏幕右邊緣的距離,以及菜單是否是抽屜式布局槽唾。

2 . 在自定義View類中獲取到自定義的屬性值。如果用戶在xml文件中自定義了屬性值光涂,我們則獲取,如果沒有顯式設(shè)置忘闻,則使用默認(rèn)值即可。

順便說一下齐佳,前面提到當(dāng)我們使用自定義屬性時,會默認(rèn)調(diào)用三個參數(shù)的構(gòu)造方法炼吴,所以我們獲取自定義屬性值的代碼也是寫在三個參數(shù)的構(gòu)造方法中。

下面是獲取屬性值的代碼:

/**
 * 當(dāng)使用了自定義屬性時會調(diào)用此方法
 * @param context
 * @param attrs
 * @param defStyleAttr
 */
public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);

    //獲取我們自定義的屬性
    TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.SlidingMenu, defStyleAttr, 0);
    int n = typedArray.getIndexCount();
    //遍歷每一個屬性
    for (int i = 0; i < n; i++) {
        int attr = typedArray.getIndex(i);
        switch (attr){
            //對我們自定義屬性的值進(jìn)行讀取
            case R.styleable.SlidingMenu_rightPadding:
                //如果在應(yīng)用樣式時沒有賦值則使用默認(rèn)值50,如果有值則直接讀取
                mMenuRightPadding = typedArray.getDimensionPixelSize(attr,
                        (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mMenuRightPadding, context.getResources().getDisplayMetrics()));
                break;
            case R.styleable.SlidingMenu_drawerType:
                isDrawerType = typedArray.getBoolean(attr, false);
                break;
            default:
                break;
        }
    }
    //釋放,一定要釋放
    typedArray.recycle();
}

3 . 上面的代碼中我們已經(jīng)可以讀取到設(shè)置的屬性值硅蹦,我們可以如下面一樣設(shè)置自定義屬性值:

<com.codekong.qq_50_slidingmenu.view.SlidingMenu
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:rightPadding="100dp"
       app:drawerType="true"
       android:scrollbars="none">
 </com.codekong.qq_50_slidingmenu.view.SlidingMenu>

4 . 使用屬性值控制具體的邏輯,我們的rightPadding一旦獲取到就會在onMeasure()方法中被設(shè)置童芹,而drawerType被獲取到就可以控制是否會調(diào)用onScrollChanged()中的代碼。代碼如下:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
   if (!once){
       once = true;
       mWapper = (LinearLayout) getChildAt(0);
       mMenu = (ViewGroup) mWapper.getChildAt(0);
       mContent = (ViewGroup) mWapper.getChildAt(1);
       //菜單和內(nèi)容區(qū)域的高度都可以保持默認(rèn)match_parent
       //菜單寬度 = 屏幕寬度 - 菜單距屏幕右側(cè)的間距
       mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
       mContent.getLayoutParams().width = mScreenWidth;
       //當(dāng)設(shè)置了其中的菜單的寬高和內(nèi)容區(qū)域的寬高之后,最外層的LinearLayout的mWapper就自動設(shè)置好了
   }
   super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    super.onScrollChanged(l, t, oldl, oldt);
    if (isDrawerType){
        float scale = l * 1.0f / mMenuWidth;  //1 ~ 0
        //調(diào)用屬性動畫,設(shè)TranslationX
        mMenu.setTranslationX(mMenuWidth * scale);
    }
}

十一署咽、給自定義View設(shè)置方法

對于我們的滑動式菜單,我們最常用的功能便是菜單的打開和關(guān)閉宁否,所以我們可以在自定義View中定義這兩個方法,方便我們的使用久锥,下面是具體的代碼:

/**
 * 打開菜單
 */
public void openMenu(){
    if (!isOpen){
        this.smoothScrollTo(0, 0);
        isOpen = true;
    }
}

/**
 * 關(guān)閉菜單
 */
public void closeMenu(){
    if (isOpen){
        this.smoothScrollTo(mMenuWidth, 0);
        isOpen = false;
    }
}

/**
 * 切換菜單
 */
public void toggleMenu(){
    if (isOpen){
        closeMenu();
    }else{
        openMenu();
    }
}

當(dāng)我們在Activity中使用時可以按下面的代碼使用:

SlidingMenu slidingMenu = (SlidingMenu) findViewById(R.id.sliding_menu);
slidingMenu.toggleMenu();

最后面放上完整的自定義View的代碼:

public class SlidingMenu extends HorizontalScrollView {
   //自定義View布局中內(nèi)嵌的最外層的LinearLayout
   private LinearLayout mWapper;
   //菜單布局
   private ViewGroup mMenu;
   //內(nèi)容布局
   private ViewGroup mContent;
   //屏幕寬度
   private int mScreenWidth;
   //菜單距屏幕右側(cè)的距離,單位dp
   private int mMenuRightPadding = 50;
   //菜單的寬度
   private int mMenuWidth;
   //定義標(biāo)志,保證onMeasure只執(zhí)行一次
   private boolean once = false;
   //菜單是否是打開狀態(tài)
   private boolean isOpen = false;
   //是否是抽屜式
   private boolean isDrawerType = false;
   /**
    * 在代碼中使用new時會調(diào)用此方法
    * @param context
    */
   public SlidingMenu(Context context) {
       this(context, null);
   }

   /**
    * 未使用自定義屬性時默認(rèn)調(diào)用
    * @param context
    * @param attrs
    */
   public SlidingMenu(Context context, AttributeSet attrs) {
       //調(diào)用三個參數(shù)的構(gòu)造方法
       this(context, attrs, 0);

   }

   /**
    * 當(dāng)使用了自定義屬性時會調(diào)用此方法
    * @param context
    * @param attrs
    * @param defStyleAttr
    */
   public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) {
       super(context, attrs, defStyleAttr);

       //獲取我們自定義的屬性
       TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs,
               R.styleable.SlidingMenu, defStyleAttr, 0);
       int n = typedArray.getIndexCount();
       //遍歷每一個屬性
       for (int i = 0; i < n; i++) {
           int attr = typedArray.getIndex(i);
           switch (attr){
               //對我們自定義屬性的值進(jìn)行讀取
               case R.styleable.SlidingMenu_rightPadding:
                   //如果在應(yīng)用樣式時沒有賦值則使用默認(rèn)值50,如果有值則直接讀取
                   mMenuRightPadding = typedArray.getDimensionPixelSize(attr,
                           (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mMenuRightPadding, context.getResources().getDisplayMetrics()));
                   break;
               case R.styleable.SlidingMenu_drawerType:
                   isDrawerType = typedArray.getBoolean(attr, false);
                   break;
               default:
                   break;
           }
       }
       //釋放
       typedArray.recycle();

       //通過以下步驟拿到屏幕寬度的像素值
       WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
       DisplayMetrics displayMetrics = new DisplayMetrics();
       windowManager.getDefaultDisplay().getMetrics(displayMetrics);
       mScreenWidth = displayMetrics.widthPixels;
   }

   /**
    * 設(shè)置子View的寬和高
    * 設(shè)置自身的寬和高
    * @param widthMeasureSpec
    * @param heightMeasureSpec
    */
   @Override
   protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
       if (!once){
           once = true;
           mWapper = (LinearLayout) getChildAt(0);
           mMenu = (ViewGroup) mWapper.getChildAt(0);
           mContent = (ViewGroup) mWapper.getChildAt(1);
           //菜單和內(nèi)容區(qū)域的高度都可以保持默認(rèn)match_parent
           //菜單寬度 = 屏幕寬度 - 菜單距屏幕右側(cè)的間距
           mMenuWidth = mMenu.getLayoutParams().width = mScreenWidth - mMenuRightPadding;
           mContent.getLayoutParams().width = mScreenWidth;
           //當(dāng)設(shè)置了其中的菜單的寬高和內(nèi)容區(qū)域的寬高之后,最外層的LinearLayout的mWapper就自動設(shè)置好了
       }
       super.onMeasure(widthMeasureSpec, heightMeasureSpec);
   }

   /**
    * 通過設(shè)置偏移量將Menu隱藏
    * @param changed
    * @param l
    * @param t
    * @param r
    * @param b
    */
   @Override
   protected void onLayout(boolean changed, int l, int t, int r, int b) {

       super.onLayout(changed, l, t, r, b);
       if (changed){
           //布局發(fā)生變化時調(diào)用(水平滾動條向右移動menu的寬度,則正好將menu隱藏)
           this.scrollTo(mMenuWidth, 0);
       }
   }

   @Override
   public boolean onTouchEvent(MotionEvent ev) {
       int action = ev.getAction();
       //按下和移動使用HorizontalScrollView的默認(rèn)處理
       switch (action){
           case MotionEvent.ACTION_UP:
               //隱藏在左邊的位置
               int scrollX = getScrollX();
               if (scrollX > mMenuWidth / 2){
                   //隱藏的部分較大, 平滑滾動不顯示菜單
                   this.smoothScrollTo(mMenuWidth, 0);
                   isOpen = false;
               }else{
                   //完全顯示菜單
                   this.smoothScrollTo(0, 0);
                   isOpen = true;
               }
               return true;
       }
       return super.onTouchEvent(ev);
   }

   /**
    * 打開菜單
    */
   public void openMenu(){
       if (!isOpen){
           this.smoothScrollTo(0, 0);
           isOpen = true;
       }
   }

   /**
    * 關(guān)閉菜單
    */
   public void closeMenu(){
       if (isOpen){
           this.smoothScrollTo(mMenuWidth, 0);
           isOpen = false;
       }
   }

   /**
    * 切換菜單
    */
   public void toggleMenu(){
       if (isOpen){
           closeMenu();
       }else{
           openMenu();
       }
   }

   /**
    * 滾動發(fā)生時調(diào)用
    * @param l  getScrollX()
    * @param t
    * @param oldl
    * @param oldt
    */
   @Override
   protected void onScrollChanged(int l, int t, int oldl, int oldt) {
       super.onScrollChanged(l, t, oldl, oldt);
       if (isDrawerType){
           float scale = l * 1.0f / mMenuWidth;  //1 ~ 0
           //調(diào)用屬性動畫,設(shè)TranslationX
           mMenu.setTranslationX(mMenuWidth * scale);
       }
   }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子歹苦,更是在濱河造成了極大的恐慌,老刑警劉巖殴瘦,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蚪腋,居然都是意外死亡,警方通過查閱死者的電腦和手機屉凯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悠砚,“玉大人,你說我怎么就攤上這事灌旧。” “怎么了枢泰?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長衡蚂。 經(jīng)常有香客問我稼稿,道長讳窟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任丽啡,我火速辦了婚禮,結(jié)果婚禮上补箍,老公的妹妹穿的比我還像新娘。我一直安慰自己坑雅,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布裹粤。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拇泣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天霉翔,我揣著相機與錄音,去河邊找鬼债朵。 笑死子眶,一個胖子當(dāng)著我的面吹牛序芦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芝加,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼藏杖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝌麸,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎来吩,沒想到半個月后敢辩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體弟疆,經(jīng)...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年怠苔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柑司。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖攒驰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玻粪,我是刑警寧澤隅津,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站饥瓷,受9級特大地震影響痹籍,放射性物質(zhì)發(fā)生泄漏呢铆。R本人自食惡果不足惜蹲缠,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望线定。 院中可真熱鬧,春花似錦斤讥、人聲如沸纱皆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铛楣。三九已至,卻和暖如春簸州,著一層夾襖步出監(jiān)牢的瞬間鉴竭,已是汗流浹背岸浑。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矢洲,地道東北人。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓兵钮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親掘譬。 傳聞我的和親對象是個殘疾皇子泰演,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,914評論 2 355

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