Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 簡單的側滑菜單實現

簡單的側滑菜單實現

編輯:關於Android編程

實現思路

利用自定義的HorizontalScrollView實現。 HorizontalScrollView中管理兩個視圖,一個視圖為“菜單”,另一個為“正文”。初始時“菜單”部分在屏幕可視區域以外。當利用HorizontalScrollView的滑動機制進行水平滑動時,將隱藏在屏幕外的“菜單”部分“拖入”屏幕可視區域。 效果增強
以自定義的方式繼承HorizontalScrollView並改寫了其中的一些方法,可以在側滑時增加一些滑動效果。比如滑動中“正文”的逐步縮小,“菜單”的逐步放大以及透明度的變化等。

實現步驟

初步示意圖
這裡寫圖片描述
初始時只會在屏幕中看見正文區域
隨著向右“滑動”,“菜單”會出現在屏幕的可視區域內
這裡寫圖片描述 代碼實現
寫一個自定義的View繼承自HorizontalScrollView
MySlidingMenu extends HorizontalScrollView

然後利用自定義的MySlidingMenu構建MainActivity中的布局

 

        
            

            
        
        
    

其中left_menu_layout就是一個簡單的LinearLayout,羅列了幾個TextView形式的菜單項,正文區域是一幅圖片

方法重寫
為了實現初始時“菜單”部分在屏幕可視區域的左側,需要重寫MySlidingMenu的一些方法。這些方法包括:
onMeasure方法:在這裡要確認一下菜單區域和正文區域的大小
onLayout方法:在這裡完成對MySlidingMenu中內容的“擺放”。
  @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        wrapper = (LinearLayout) this.getChildAt(0);
        menu = wrapper.getChildAt(0);
        content = wrapper.getChildAt(1);
        menuWidth = screenWidth - menuRightPadding;
        menu.getLayoutParams().width = menuWidth;
        content.getLayoutParams().width = screenWidth;

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed) {
            this.scrollTo(menuWidth, 0);
        }
    }

在onMeasure方法中screenWidth是屏幕的寬度:

 DisplayMetrics outMetrics = new DisplayMetrics();
        ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(outMetrics);
        screenWidth = outMetrics.widthPixels;

menuRightPadding是“菜單”打開後,菜單距離屏幕右側的距離。該值可以被當做一個自定義屬性在布局文件中由使用者傳入。默認值為80dp

 TypedArray t = context.obtainStyledAttributes(attrs, R.styleable.MySlidingMenu);
        menuRightPadding = t.getDimensionPixelSize(R.styleable.MySlidingMenu_menu_padding,
                (int) TypedValue.applyDimension(
                        TypedValue.COMPLEX_UNIT_DIP, 80, getResources().getDisplayMetrics()));
        t.recycle();

在確定了“菜單”部分的寬度後,在onLayout方法中調用scrollTo方法,該方法就是將MySlidingMenu的“內容區域”的左邊緣移動到MySlidingMenu左邊緣的左側,距離恰好是“菜單”的寬度。這樣就保證了“菜單”恰好位於屏幕可視區域之外。
此時就可以運行代碼,實現“菜單”的側滑了。
這裡寫圖片描述

效果增強
基本效果實現了,接下來利用代碼來實現效果的增強:
如果在滑動過程中松手,菜單已經顯示的區域如果大於菜單尺寸的1/2則應該自動的完成菜單顯示的後續滑動,反之則應該讓菜單完成收起的後續動作。
上述邏輯寫在MySlidingMenu的onTouchEvent中,因為HorizontalScrollView本身實現了一套onTouchEvent的邏輯,這裡我們只針對MontionEvent的Action_Up動作即可:
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        if (action == MotionEvent.ACTION_UP) {
            int sx = getScrollX();
            if (sx >= menuWidth / 2) {
                smoothScrollTo(menuWidth, 0);
                isOpen = false;
            } else {
                smoothScrollTo(0, 0);
                isOpen = true;
            }
            return true;
        }
        return super.onTouchEvent(ev);
    }

這裡在完成滑動時直接調用了HorizontalScrollView的smoothScrollTo方法,這樣可以實現一個平滑的滑動過程,而不會像scrollTo那樣瞬間完成滑動。

在上面的實現中,“菜單”是從左側被“拖”出來的,接下來實現一種正文好像覆蓋在“菜單”上面的感覺,先看示意圖,對比一下兩者的差異:
這裡寫圖片描述
可以明顯看出兩者的效果差異吧。
要從“拖出”效果轉為“覆蓋”效果,僅僅需要一行代碼:
重寫一下父類的onScrollChanged方法即可:

@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {

        ViewHelper.setTranslationX(menu, l);
        super.onScrollChanged(l, t, oldl, oldt);
    }

其中ViewHelper是nineoldandroids.jar中的一個類,nineoldandroids不用過多介紹了,它是一個兼容3.0以下版本實現屬性動畫的一個安卓類庫。setTranslationX的意思就是設定“菜單”這個視圖的translationX的值。方法中將menu視圖的translationX的值設定為了onScrollChanged方法的第一個參數值。這是因為:
當MySlidingMenu的scrollTo方法被調用的時候(scrollBy和smoothScrollTo方法內部也是在調用scrollTo方法),scrollTo方法內部做的事情就是設定好滑動終止時的目標scrollX和scrollY的值以及滑動開始時的scrollX與scrollY的值,然後調用onScrollChanged方法,將這四個值作為onScrollChanged方法的四個參數,因此l參數的意思實際就是當滑動結束時“菜單”視圖的scrollX的值。
MySlidingMenu的本身的視圖寬度為屏幕的寬度,而MySlidingMenu中管理的內容是“菜單”視圖+“正文”視圖,內容的寬度是大於MySlidingMenu本身的寬度的,scrollX代表的就是MySlidingMenu現實的內容左邊緣與MySlidingMenu本身左邊緣的距離。
如果此時不做任何額外的操作,那麼“菜單”視圖停留在MySlidingMenu左側邊緣的左側,距離MySlidingMenu左側邊緣scrollX個像素。現在希望它能夠出現在可視區域中,也就是讓“菜單”視圖的左邊緣恰好出現在MySlidingMenu的左邊緣,那就需要讓“菜單”視圖從當前自己的左邊緣開始再多滑動scrollX個像素的距離。如何滑動呢,就設定“菜單”視圖的translationX屬性值即可,translationX屬性值代表讓視圖產生移動,視圖移動後左側邊緣與視圖left屬性之間的距離(這部分內容的詳情可以參考我的另一篇blogView的坐標系)。所以只要設定“菜單”視圖的translationX屬性值為滑動結束後的scrollX的值即可,這樣每次滑動結束後,利用translationX再讓“菜單”視圖多滑動scrollX個像素值。這樣就實現了每次滑動時,“菜單”視圖始終都是左側與MySlidingMenu的左側保持一致的效果。

接下來再增加一些滑動中的效果。比如隨著滑動,讓“內容”區域產生一個由大到小的變化,讓“菜單”區域產生一個由小到大的變化,並伴隨一個透明度的變化:
這一切的發生都是隨著滑動而發生的,因此這裡需要找到一個隨著滑動而不斷變化的比例值:

@Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
    float scale = l*1.0f/menuWidth;
        ViewHelper.setTranslationX(menu, l);
        super.onScrollChanged(l, t, oldl, oldt);
    }

隨著滑動l的值會不斷發生變化,但是“菜單”的寬度是在onMeasure方法中設定好的,並不會變化,而滑動的整體變化過程或者說l的取值范圍就是從0到menuWidth。有了這個scale後,就可以利用它實現各種滑動過程中的變化了:

 @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        //隨著滑動,l的值不斷變化(從menuWidth到0)。將絕對值值轉化為一個比值
        //scale的變化區間是1--->0
        float scale = l*1.0f/menuWidth;
        ViewHelper.setTranslationX(menu, l);
        //隨著拖動,content區域由大到小從100%--->70%左右
        ViewHelper.setScaleX(content,0.7f+0.3f*scale);
        ViewHelper.setScaleY(content,0.7f+0.3f*scale);
        ViewHelper.setPivotX(content,0);
        ViewHelper.setPivotY(content,content.getHeight()/2);
        //隨著拖動,菜單區域的透明度在變化,變化區間大概是0.7--->1
        ViewHelper.setAlpha(menu,0.5f+0.5f*(1-scale));
        //隨著拖動,菜單區域的大小在變化變化區間大概是0.7--->1
        ViewHelper.setScaleX(menu,0.7f+0.3f*(1-scale));
        ViewHelper.setScaleY(menu,0.7f+0.3f*(1-scale));
        super.onScrollChanged(l, t, oldl, oldt);
    }

代碼運行後的效果如圖所示:
這裡寫圖片描述

還可以再增加一點效果。此時的效果是隨著拖動“菜單”視圖恰好每次都是出現在MySlidingMenu的左邊緣。如果每次不讓“菜單”視圖都移動scrollX的距離,而是移動的少一點,這樣在MySlidingMenu的滑動過程除了上述已經有的效果外,還可以再帶著一點“菜單”平滑拖出的效果。
只需要修改setTranslationX部分即可,原先移動l,現在讓l乘以一個比例值,就可以不移動scrollX了:

 @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {

        //隨著滑動,l的值不斷變化(從menuWidth到0)。將絕對值值轉化為一個比值
        //scale的變化區間是1--->0
        float scale = l*1.0f/menuWidth;
        //ViewHelper.setTranslationX(menu, l);
        ViewHelper.setTranslationX(menu, l*0.7f);
        //隨著拖動,content區域由大到小
        //但是並不是到0,大概是從100%--->70%左右
        ViewHelper.setScaleX(content,0.7f+0.3f*scale);
        ViewHelper.setScaleY(content,0.7f+0.3f*scale);
        ViewHelper.setPivotX(content,0);
        ViewHelper.setPivotY(content,content.getHeight()/2);
        //隨著拖動,菜單區域的透明度在變化
        //變化區間大概是0.7--->1
        ViewHelper.setAlpha(menu,0.5f+0.5f*(1-scale));
        //隨著拖動,菜單區域的大小在變化
        //變化區間大概是0.7--->1
        ViewHelper.setScaleX(menu,0.7f+0.3f*(1-scale));
        ViewHelper.setScaleY(menu,0.7f+0.3f*(1-scale));

        super.onScrollChanged(l, t, oldl, oldt);

    }

看一下這次的運行效果:
這裡寫圖片描述
可以看到“菜單”區域除了透明度、大小變化之外,還有了側拉效果。

該策滑菜單的基本實現需要掌握自定義View的基本知識,以及scrollTo的用法。在效果增強部分,需要先理解View中的幾個坐標點的差異包括left,scrollX,translationX等,這樣才能逐步實現效果。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved