QQ測拉效果實現(一)

前言:總有一天,你會成爲你想象的那樣。

轉載本文請註明出處,尊重原創:

如果想第一時間收到文章更新,可以微信掃描二維碼關注我的公衆號,或者微信直接搜索“Android小菜”進行關注,所有的文章會比CSDN更快一步:

覺得有幫助可以讚賞或者點個贊,都是對博主的支持。

本篇文章開始連續三篇會實現類似QQ測拉效果的自定義控件。分別使用不同的方式來實現同一效果。


本篇使用方式一來實現:HorizontalScrollView + LinearLayout + scrollTo + 屬性動畫。

說明:HorizontalScrollView 自動實現了滑動功能,裏面放置一個LinearLayout,LinearLayout橫向裏面放置兩個控件,左側菜單+主頁面佈局。



本文會從基本功能再到“特效”的步驟循序進行。


首先不加入動畫,先實現基本側滑功能,要實現的功能如下gif:

基礎功能由於很簡單,直接把代碼貼在下面:

public class QQSlidingMenu extends HorizontalScrollView {

    /**
     * 屏幕寬度
     */
    private final int mScreenWidth;

    /**
     * 代表左側菜單和內部區域的父容器
     */
    private LinearLayout mWapper;

    /**
     * 左側菜單區域
     */
    private ViewGroup mLeftMenu;

    /**
     * 主頁面內容區域
     */
    private ViewGroup mContentMenu;

    /**
     * 左側菜單完全展示距離右側的距離值dp
     */
    private int mLeftMenuRightPadding = 50;

    /**
     * 左側菜單的寬度
     */
    private int mLeftMenuWidth;

    /**
     * onMeasure只測量一次
     */
    private boolean once;

    public QQSlidingMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        //獲取屏幕寬度
        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        DisplayMetrics metrics = new DisplayMetrics();
        wm.getDefaultDisplay().getMetrics(metrics);
        mScreenWidth = metrics.widthPixels;

        /**---------  dp--->px  ---------**/
        mLeftMenuRightPadding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,context.getResources().getDisplayMetrics());
    }

    /**
     * 測量孩子的大小,確定自己的大小
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        if(!once){

            mWapper = (LinearLayout) this.getChildAt(0);
            mLeftMenu = (ViewGroup) mWapper.getChildAt(0);
            mContentMenu = (ViewGroup) mWapper.getChildAt(1);

            //設置左右菜單的寬度
            mLeftMenuWidth = mLeftMenu.getLayoutParams().width = mScreenWidth - mLeftMenuRightPadding;
            mContentMenu.getLayoutParams().width = mScreenWidth;

            once = true;
        }
        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){
            scrollTo(mLeftMenuWidth,0);
        }
    }

    //滑動事件HorizontalScrollView已經幫忙給處理了,所以不需要down和move的操作
    @Override
    public boolean onTouchEvent(MotionEvent ev) {

        switch (ev.getAction()) {
            case MotionEvent.ACTION_UP:
                // 判斷目前滑動到的位置,讓控件過度到某種狀態
                // 如果左側菜單滑動超過了左側菜單的一半則展示左側菜單,如果滑動少於左側菜單一半則展示主頁面,隱藏左菜單
                int scrollX = getScrollX();
                if(scrollX >= mLeftMenuWidth/2){
                    smoothScrollTo(mLeftMenuWidth,0);
                }else{
                    smoothScrollTo(0,0);
                }
                return true;
         }

        return super.onTouchEvent(ev);

    }
}

沒錯,上面十幾行代碼就實現了最基本功能了。因爲HorizontalScrollView 已經具備了處理滑動事件的功能,我們只需要關心在哪個位置擡起手指(鼠標),以及讓控件平滑滑動到哪個位置。

然後對上面的代碼做個解析:

首先在構造方法裏面拿到屏幕的寬度,這個寬度待會要設置HorizontalScrollView孩子控件的寬度,接着是dp-->px的轉換,因爲要設置左側菜單控件距離屏幕右側的Padding值,這裏定義爲50dp。

然後重寫onMeasure方法,在裏面分別測量了自定義QQSlidingMenu控件的孩子控件的大小,因爲佈局文件中QQSlidingMenu的xml裏面是一個水平的LinearLayout控件,它裏面包含了兩個佈局,分別是左側菜單的佈局,和主頁內容的佈局。然後首先拿到LinearLayout實例,再根據getChildAt(i),分別拿到左側菜單和主頁內容的佈局實例,強轉爲ViewGroup類型。爲了方式多次測量,定義了一個標誌位,表示只需要測量一次。對於左側菜單的寬度=屏幕寬度-距離右側的padding值;對於主頁面的寬度就爲屏幕的寬度。

然後重寫onLayout方法,對孩子控件進行位置包房,由於默認情況下是下面擺放:

其中紫色區域是自定義的QQSlidingMenu。顯然默認是錯誤的,因此要改變控件的位置,看到只是簡單的一行代碼就設置了控件的初識位置。scrollTo到左側菜單的寬度,那麼測試的效果如下:

佈局擺放好了,往下就是滑動事件了,發現也很簡單,因爲咱們是繼承的HorizontalScrollView ,它已經默認做好了MOVE和DOWN事件了,所以只需要判斷一下UP事件就可以了。在UP的時候,判斷目前滑動到的位置,讓控件過度到某種狀態(是顯示菜單還是隱藏菜單);如果左側菜單往右滑動超過了左側菜單的一半則展示左側菜單,如果往右滑動少於左側菜單一半則展示主頁面,隱藏左菜單。並調用smoothScrollTo,讓佈局平滑過渡到某個值。然後說一下getScroll()這個值是多少,看下面一張圖:

灰色筆描述的就是getScroll()值,他表示控件相對屏幕劃過的距離,值大於0,表示控件是左滑得到的值,小於0,表示控件右滑得到的值。


上面屬於最基本的功能實現,我們考慮,在控件的代碼中,我按照自己的意願寫了50dp的padding值,那麼別人如果想設置爲100dp,或者150dp怎麼辦,難道要修改代碼嗎?所以,有必要加入自定義屬性,通過這種方式在xml中,手動設置padding,而不是去修改代碼:

新建一個名稱爲attr的xml文件:

然後在這裏面做一點文章:

上面是定義了一個屬性,待會再xml佈局中我們就要使用該自定義的屬性。

QQSlidingMenu控件的構造方法中加入如下代碼:

TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QQSlidingMenu);
        int count = array.getIndexCount();

        for (int i = 0; i < count; i++) {
            int attr = array.getIndex(i);
            switch (attr) {
                case R.styleable.QQSlidingMenu_mRightPadding:
                    mLeftMenuRightPadding = array.getDimensionPixelSize(attr,
                            (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,
                                    context.getResources().getDisplayMetrics()));
                    break;

                default:
                    break;
                }
        }

        array.recycle();

然後在佈局文件中引入自定義屬性:

我們自定義屬性的方式,設置padding值爲100dp,那麼此時運行後,左側菜單距離屏幕右側的寬度肯定是會增加的。

此時運行程序看一下側滑菜單展示的樣式:


以上加上了自定義屬性,緊接着,我們加上一個menu按鈕,來實現點擊按鈕打開左側菜單的功能:


在自定義QQSlidingMenu裏面,加入如下打開和關閉的代碼,並且提供一個共有的toogle方法:


當然,在滑動的時候,也要修改一下標誌位:


再運行程序:



以上是本篇所講內容,下一篇會修改這裏的代碼,加入一些動畫,實現抽屜效果,



想第一時間查看文章,請關注公衆號:“Android小菜”。











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章