側(cè)滑菜單——方式二(使用ViewDragHelper)

在此例子中DragViewGroup繼承于LinearLayout

第一步 初始化ViewDragHelper躺枕,在構(gòu)造方法中進(jìn)行

//通過靜態(tài)工廠方法創(chuàng)建
viewDragHelper=ViewDragHelper.create(this,callback);//this指parentView,在這里就是自定義ViewGroup氓栈;callback是使用ViewDragHelper的核心

第二步 攔截事件渣磷,此步驟必不可少

@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //事件攔截給viewDragHelper
        return viewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //將觸摸事件傳遞給viewDragHelper,此操作必不可少
        viewDragHelper.processTouchEvent(event);
        return true;
    }

第三步 處理computScroll方法授瘦,和使用Scroller一樣幸海,因?yàn)閂iewDragHelper內(nèi)部就是使用了Scroller來實(shí)現(xiàn)的
這里一般情況下可以套用以下模板

@Override
    public void computeScroll() {
        super.computeScroll();
        if(viewDragHelper.continueSettling(true)){
            ViewCompat.postInvalidateOnAnimation(this);//刷新帶有動畫
        }
    }
  • ViewCompat.postInvalidateOnAnimation(this)相當(dāng)于使用scroller的時候必須要調(diào)用invalidate刷新頁面,并且不斷循環(huán)調(diào)用

第四步 也是最關(guān)鍵的一步奥务,處理回調(diào)Callback,在他的內(nèi)部有很多方法物独,我們重寫可以實(shí)現(xiàn)很多效果

  • 首先會重寫tryCaptureView方法 ,此方法可以指定哪個View可以被拖動
  • 重寫clampViewPositionHorizontal氯葬、clampViewPositionVertical方法可以實(shí)現(xiàn)水平和垂直的滑動挡篓,默認(rèn)返回為0,可以限制滑動區(qū)域
  • 重寫onViewCaptured方法可以實(shí)現(xiàn)手指觸摸到View時的效果
  • 重寫onViewReleased方法可以實(shí)現(xiàn)手指離開屏幕時的一些功能
  • 重寫onViewPositionChanged方法在事件位置變化時可以實(shí)現(xiàn)一些動態(tài)效果
  • 重寫onViewDragStateChanged方法在拖拽狀態(tài)變化時調(diào)用
private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return content==child;//判斷是否滑動的子View是內(nèi)容區(qū)域
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {//水平滑動,left表示垂直方向上的位置,dx表示較前次的偏移量
            return left;
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {//垂直滑動官研,top表示垂直方向上的位置秽澳,dy表示較前次的偏移量
            return super.clampViewPositionVertical(child, top, dy);//默認(rèn)為0
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {//手指離開屏幕
            super.onViewReleased(releasedChild, xvel, yvel);
            //手指抬起后緩慢移動到指定位置
            if(content.getLeft()<menu.getWidth()/2){
                //關(guān)閉菜單
                //相當(dāng)于scroller的startScroll方法
                viewDragHelper.smoothSlideViewTo(content,0,0);
                //刷新帶有動畫
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }else{
                //打開菜單
                //相當(dāng)于scroller的startScroll方法
                viewDragHelper.smoothSlideViewTo(content,menu.getWidth(),0);
                //刷新帶有動畫
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
        }
    };

在onFinishInflate方法中按順序定義定義menu,content
在onSizeChanged方法中獲取子View的寬

最終效果就能實(shí)現(xiàn)抽屜式的側(cè)滑菜單

slide.gif

完整代碼如下

public class DragViewGroup extends LinearLayout {
    private ViewDragHelper viewDragHelper;
    private ViewGroup menu,content;//菜單和內(nèi)容
    private int mScreenWidth;
    //dp
    private int menuRightMargin;

    private boolean once;

    private ViewDragHelper.Callback callback=new ViewDragHelper.Callback() {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return content==child;//判斷是否滑動的子View是內(nèi)容區(qū)域
        }

        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {//水平滑動
            return Math.min(Math.max(0,left),mScreenWidth-menuRightMargin);//限制滑動區(qū)域在屏幕左邊距到menu右邊距
        }

        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {//垂直滑動
            return super.clampViewPositionVertical(child, top, dy);//默認(rèn)為0
        }

        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {//手指離開屏幕
            super.onViewReleased(releasedChild, xvel, yvel);
            //手指抬起后緩慢移動到指定位置
            if(content.getLeft()<menu.getWidth()/2){
                //關(guān)閉菜單
                //相當(dāng)于scroller的startScroll方法
                viewDragHelper.smoothSlideViewTo(content,0,0);
                //刷新帶有動畫
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }else{
                //打開菜單
                //相當(dāng)于scroller的startScroll方法
                viewDragHelper.smoothSlideViewTo(content,menu.getWidth(),0);
                //刷新帶有動畫
                ViewCompat.postInvalidateOnAnimation(DragViewGroup.this);
            }
        }
    };

    public DragViewGroup(Context context) {
        this(context,null);
    }

    public DragViewGroup(Context context, AttributeSet attrs) {
        this(context,attrs,0);
    }

    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化viewDragHelper
        viewDragHelper=ViewDragHelper.create(this,callback);

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

        TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.DragViewGroup);
        menuRightMargin= (int) ta.getDimension(R.styleable.DragViewGroup_menuRightMargin,TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,50,getResources().getDisplayMetrics()));
        ta.recycle();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        menu= (ViewGroup) getChildAt(0);
        content= (ViewGroup) getChildAt(1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        menu.getLayoutParams().width=mScreenWidth-menuRightMargin;
        content.getLayoutParams().width=mScreenWidth;

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        content.layout(0,0,content.getWidth(),content.getHeight());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return viewDragHelper.shouldInterceptTouchEvent(ev);//事件攔截給viewDragHelper
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //將觸摸事件傳遞給viewDragHelper戏羽,此操作必不可少
        viewDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        super.computeScroll();
        if(viewDragHelper.continueSettling(true)){
            ViewCompat.postInvalidateOnAnimation(this);//刷新帶有動畫
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LinearLayout.LayoutParams(getContext(),attrs);
    }
}

menu

<?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"
    android:background="@color/colorAccent">

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

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img1"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@mipmap/ic_launcher" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:text="第1個item"
                android:layout_toRightOf="@id/img1"
                android:layout_centerVertical="true"/>
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img2"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@mipmap/ic_launcher" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:text="第2個item"
                android:layout_toRightOf="@id/img2"
                android:layout_centerVertical="true"/>
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img3"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@mipmap/ic_launcher" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:text="第3個item"
                android:layout_toRightOf="@id/img3"
                android:layout_centerVertical="true"/>
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img4"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@mipmap/ic_launcher" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:text="第4個item"
                android:layout_toRightOf="@id/img4"
                android:layout_centerVertical="true"/>
        </RelativeLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <ImageView
                android:id="@+id/img5"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_centerVertical="true"
                android:layout_marginLeft="20dp"
                android:layout_marginTop="20dp"
                android:src="@mipmap/ic_launcher" />
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textSize="20sp"
                android:textColor="#ffffff"
                android:text="第5個item"
                android:layout_toRightOf="@id/img5"
                android:layout_centerVertical="true"/>
        </RelativeLayout>
    </LinearLayout>
</RelativeLayout>

activity_main

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


    <com.scrollerdemo.DragViewGroup 
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorAccent"
        app:menuRightMargin="100dp">

        <include layout="@layout/menu" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="@color/colorPrimary"
            android:gravity="center"
            >
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#ffffff"
                android:text="helloworld"
                android:textSize="30sp"/>
        </LinearLayout>
    </com.scrollerdemo.DragViewGroup>

    
</RelativeLayout>

自定義屬性

<declare-styleable name="DragViewGroup">
        <attr name="menuRightMargin" format="dimension"/>
    </declare-styleable>

繼續(xù)進(jìn)階担神,為側(cè)滑菜單增加動畫效果

只需要在callback內(nèi)部重寫onViewPositionChanged方法
代碼如下

@Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            float scale = left * 1f / menu.getWidth();//0 ~ 1
            float contentScale = 1 - scale * 0.2f;//1 ~ 0.8
            float menuScale = 0.7f + scale * 0.3f;//0.7 ~ 1
            float menuAlpha = 0.6f + scale * 0.4f;//0.6 ~ 1
            float menuTransX = 0.3f - 0.3f * scale;//0.3 ~ 0

            //content
            ViewHelper.setPivotX(content, 0);
            ViewHelper.setPivotY(content, content.getHeight() / 2);
            ViewHelper.setScaleX(content, contentScale);
            ViewHelper.setScaleY(content, contentScale);
            //menu
            ViewHelper.setTranslationX(menu, -menuTransX * menu.getWidth());
            ViewHelper.setAlpha(menu, menuAlpha);
            ViewHelper.setScaleX(menu, menuScale);
            ViewHelper.setScaleY(menu, menuScale);
        }

效果如下

slideanim.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市始花,隨后出現(xiàn)的幾起案子妄讯,更是在濱河造成了極大的恐慌,老刑警劉巖酷宵,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亥贸,死亡現(xiàn)場離奇詭異,居然都是意外死亡浇垦,警方通過查閱死者的電腦和手機(jī)炕置,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來男韧,“玉大人朴摊,你說我怎么就攤上這事〈寺牵” “怎么了仍劈?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長寡壮。 經(jīng)常有香客問我,道長讹弯,這世上最難降的妖魔是什么况既? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮组民,結(jié)果婚禮上棒仍,老公的妹妹穿的比我還像新娘。我一直安慰自己臭胜,他們只是感情好莫其,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著耸三,像睡著了一般乱陡。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上仪壮,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天憨颠,我揣著相機(jī)與錄音,去河邊找鬼。 笑死爽彤,一個胖子當(dāng)著我的面吹牛养盗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播适篙,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼往核,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了嚷节?” 一聲冷哼從身側(cè)響起聂儒,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎丹喻,沒想到半個月后薄货,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡碍论,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年谅猾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鳍悠。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡税娜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出藏研,到底是詐尸還是另有隱情敬矩,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布蠢挡,位于F島的核電站弧岳,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏业踏。R本人自食惡果不足惜禽炬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勤家。 院中可真熱鬧腹尖,春花似錦、人聲如沸伐脖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讼庇。三九已至绎巨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蠕啄,已是汗流浹背认烁。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人却嗡。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓舶沛,卻偏偏與公主長得像,于是被迫代替她去往敵國和親窗价。 傳聞我的和親對象是個殘疾皇子如庭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

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