重寫ViewGroup並藉助ViewDragHelper實現各種拖拽交互效果(一)

一般實現比較複雜的交互效果,都會選擇重寫ViewGroup,並通過onTouchEvent和onInterceptTouchEvent等實現對各種事件的處理,但對事件的處理是很不容易的一個事情。

本文主要是藉助v4包中的ViewDragHelper這個幫助類,來重寫ViewGroup,把事件完全交給幫助類去完成,並藉助幫助類的幾個回調方法來完成各種複雜交互效果,完全避開了事件處理。

對ViewDragHelper的使用,網上有很多資料,在此就不重新介紹了,這裏我通過兩個實現的例子,以及例子中的註釋,來讓大家明白怎麼輕鬆實現各種效果。

一、帶手柄的側滑菜單效果HandleDrawerLayout

Android v4包中自帶側滑菜單效果DrawerLayout是很好的一種交互,但是某些需求下,需要多一個類似手柄的東西來拉開和關閉側滑菜單,用DrawerLayout是嚐遍各種方式都無法實現。看以下效果圖就明白了


1、佈局文件:

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

    <!--內部的佈局需要按照1、2、3的順序,3嵌套4、5佈局的結構來佈局-->
    <com.dway.testwork.viewdrag.HandleDrawerLayout
        android:id="@+id/hdl_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!--1 內容佈局-->
        <FrameLayout
            android:id="@+id/hdl_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#f7f7f7">
        </FrameLayout>

        <!--2 內容佈局上面的半透明佈局-->
        <View
            android:id="@+id/hdl_scrim"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#7f000000"/>

        <!--3 側滑菜單佈局和手柄佈局的父佈局-->
        <LinearLayout
            android:id="@+id/hdl_drawer_group"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:orientation="horizontal">
            <!--4 側滑菜單佈局-->
            <FrameLayout
                android:id="@+id/hdl_menu_view"
                android:layout_width="245dp"
                android:layout_height="match_parent"
                android:background="#2d3144">
            </FrameLayout>
            <!--5 側滑手柄佈局-->
            <RelativeLayout
                android:id="@+id/hdl_handle_view"
                android:layout_width="40dp"
                android:layout_height="173dp"
                android:gravity="center"
                android:layout_gravity="center_vertical"
                android:background="#3fff00ff">
                <TextView
                    android:id="@+id/hdl_handle_view_text"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:ems="1"
                    android:maxEms="1"
                    android:gravity="center"
                    android:textSize="23sp"
                    android:text="我是手柄"
                    android:layout_gravity="center_vertical" />
            </RelativeLayout>
        </LinearLayout>
    </com.dway.testwork.viewdrag.HandleDrawerLayout>

</FrameLayout>
2、佈局類HandleDrawerLayout.java:

package com.dway.testwork.viewdrag;

import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * 帶手柄的側滑菜單佈局。
 * drawer收起的時候,menu不可見,但是handle可見
 * 佈局內部結構包含:content、scrim(drawer打開後的半透明背景)、drawer(爲橫向LinearLayout佈局,包含menu和handle)
 * Created by dway on 2017/12/19.
 */
public class HandleDrawerLayout extends ViewGroup {

    //內容view
    private View mContentView;
    //當側滑菜單展開時,顯示在mContentView上面的半透明view
    private View mScrimView;
    //側滑菜單和手柄組成的佈局,因爲側滑菜單和手柄是同時移動的,所以套了一層父佈局,方便一起移動
    private ViewGroup mDrawerGroup;
    //mDrawerGroup中的菜單view
    private View mMenuView;
    //mDrawerGroup中的手柄view
    private View mHandleView;

    //強大的幫助類
    private ViewDragHelper mHelper;

    //菜單展開的程度。取值在0到1之間,0表示側滑菜單隱藏,1表示側滑菜單完全展開
    private float mOpenPercent = 0;

    private boolean mInLayout = false;
    private boolean mFirstLayout = true;

    public HandleDrawerLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                // 限定child橫向的座標範圍:
                // 參數left是child想要移動到left位置(僅僅是想移動,但還沒移動)
                // 如果不想child在X軸上被移動,返回0
                if(child == mDrawerGroup){
                    // 這裏代表-mMenuView.getMeasuredWidth() <= left <= 0
                    // 即child的橫向座標只能在這個範圍內
                    return Math.max(-mMenuView.getMeasuredWidth(), Math.min(left, 0));
                }
                return 0;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                // 限定child縱向的座標範圍,此處暫沒用到
                return super.clampViewPositionVertical(child, top, dy);
            }

            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                // 粗碰child時對child進行嘗試捕獲,返回true代表該view可以被捕獲,false則相反
                // 比如手指按下child這個view時,如果需要交互操作則返回true
                return child == mDrawerGroup;
            }

            @Override
            public void onEdgeDragStarted(int edgeFlags, int pointerId) {
                // 邊緣檢測,可通過下面的mHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT)設置左右上下邊緣檢測
                // 以下代表屏幕左邊緣划進來,強制捕獲到mDrawerGroup,相當於人工的tryCaptureView
                mHelper.captureChildView(mDrawerGroup, pointerId);
            }

            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                // 鬆開手的時候,釋放view,根據當前速度做相應處理
                if(releasedChild == mDrawerGroup){
                    int menuViewWidth = mMenuView.getWidth();
                    float offset = (menuViewWidth + releasedChild.getLeft()) * 1.0f / menuViewWidth;
                    // 設置釋放後的view慢慢移動到指定位置
                    mHelper.settleCapturedViewAt(xvel > 0 || xvel == 0 && offset > 0.5f ? 0 : -menuViewWidth, releasedChild.getTop());
                    // 要調用invalidate()纔會開始移動
                    invalidate();
                }
            }

            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                // 被捕獲的view位置改變的回調,left和top爲changedView即將移動到的位置
                if(changedView == mDrawerGroup){
                    int menuViewWidth = mMenuView.getWidth();
                    mOpenPercent = (float) (menuViewWidth + left) / menuViewWidth;

                    mScrimView.setAlpha(mOpenPercent);
                    if(floatCompare(mOpenPercent, 0f)){
                        mScrimView.setVisibility(GONE);
                    }else{
                        mScrimView.setVisibility(VISIBLE);
                    }

                    if(mDrawerListener != null){
                        mDrawerListener.onDrawer(mOpenPercent);
                    }
                }
            }

            @Override
            public int getViewHorizontalDragRange(View child) {
                //指定child橫向可拖拽的範圍
                return child == mDrawerGroup ? mMenuView.getWidth() : 0;
            }
        });
        // 設置左邊緣檢測,即從屏幕左邊划進屏幕時,會回調onEdgeDragStarted
        mHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // 設置各個子view的大小
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);

        // 按照xml文件的佈局,獲取各個子view
        mContentView = getChildAt(0);
        mScrimView = getChildAt(1);
        mDrawerGroup = (ViewGroup) getChildAt(2);
        mMenuView = mDrawerGroup.getChildAt(0);
        mHandleView = mDrawerGroup.getChildAt(1);

        MarginLayoutParams lp = (MarginLayoutParams) mContentView.getLayoutParams();
        int contentWidthSpec = MeasureSpec.makeMeasureSpec(
                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
        int contentHeightSpec = MeasureSpec.makeMeasureSpec(
                heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
        mContentView.measure(contentWidthSpec, contentHeightSpec);

        lp = (MarginLayoutParams) mScrimView.getLayoutParams();
        int bgWidthSpec = MeasureSpec.makeMeasureSpec(
                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
        int bgHeightSpec = MeasureSpec.makeMeasureSpec(
                heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
        mScrimView.measure(bgWidthSpec, bgHeightSpec);

        lp = (MarginLayoutParams) mDrawerGroup.getLayoutParams();
        int menuGroupWidthSpec = getChildMeasureSpec(widthMeasureSpec,
                lp.leftMargin + lp.rightMargin, lp.width);
        int menuGroupHeightSpec = getChildMeasureSpec(heightMeasureSpec,
                lp.topMargin + lp.bottomMargin, lp.height);
        mDrawerGroup.measure(menuGroupWidthSpec, menuGroupHeightSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        // 設置各子view的位置,注意第一次初始化位置和以後設置的位置略有區別
        mInLayout = true;
        MarginLayoutParams lp = (MarginLayoutParams) mContentView.getLayoutParams();
        mContentView.layout(lp.leftMargin, lp.topMargin,
                lp.leftMargin + mContentView.getMeasuredWidth(),
                lp.topMargin + mContentView.getMeasuredHeight());

        lp = (MarginLayoutParams) mScrimView.getLayoutParams();
        mScrimView.layout(lp.leftMargin, lp.topMargin,
                lp.leftMargin + mScrimView.getMeasuredWidth(),
                lp.topMargin + mScrimView.getMeasuredHeight());

        lp = (MarginLayoutParams) mDrawerGroup.getLayoutParams();
        int groupLeft;// = - mMenuView.getMeasuredWidth() + lp.leftMargin;
        if(mFirstLayout){
            groupLeft = - mMenuView.getMeasuredWidth() + lp.leftMargin;
        }else{
            groupLeft = mDrawerGroup.getLeft();
        }
        mDrawerGroup.layout(groupLeft, lp.topMargin,
                groupLeft + mDrawerGroup.getMeasuredWidth(),
                lp.topMargin + mDrawerGroup.getMeasuredHeight());

        initScrimView();

        mInLayout = false;
        mFirstLayout = false;
    }

    @Override
    public void requestLayout() {
        if(!mInLayout) {
            super.requestLayout();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mFirstLayout = true;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mFirstLayout = true;
    }

    private void initScrimView(){
        if(mFirstLayout && mScrimView != null){
            mScrimView.setAlpha(mOpenPercent);
            if(floatCompare(mOpenPercent, 0f)){
                mScrimView.setVisibility(GONE);
            }else{
                mScrimView.setVisibility(VISIBLE);
            }
            mScrimView.setOnClickListener(onClickListener);
        }
    }

    private OnClickListener onClickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if(isDrawerOpen()){
                closeDrawer();
            }
        }
    };

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 把事件處理交給ViewDragHelper
        return mHelper.shouldInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 把事件處理交給ViewDragHelper
        mHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        // 滾動過程的計算,也是交給ViewDragHelper,按以下這麼寫就好了
        if (mHelper.continueSettling(true)) {
            invalidate();
        }
    }

    // 以下三個方法需要重寫,沒啥特殊要求直接返回MarginLayoutParams就可以了

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

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

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }


    /**
     * 兩個float類型的大小比較
     * @return true 相等,false 不相等
     */
    private boolean floatCompare(float f1, float f2){
        return Math.abs(f1 - f2) < Float.MIN_VALUE;
    }

    /**
     * 是否drawer已打開。float相等直接比較可能有存在問題
     */
    public boolean isDrawerOpen(){
        return floatCompare(mOpenPercent, 1f);
    }

    /**
     * 打開drawer
     */
    public void openDrawer() {
        mOpenPercent = 1.0f;
        mHelper.smoothSlideViewTo(mDrawerGroup, 0, mDrawerGroup.getTop());
        invalidate();
    }

    /**
     * 關閉drawer
     */
    public void closeDrawer() {
        mOpenPercent = 0.0f;
        mHelper.smoothSlideViewTo(mDrawerGroup, -mMenuView.getWidth(), mDrawerGroup.getTop());
        invalidate();
    }

    private OnDrawerListener mDrawerListener = null;

    /**
     * 外部可設置監聽drawer的位置回調
     * @param listener
     */
    public void setOnDrawerListener(OnDrawerListener listener) {
        mDrawerListener = listener;
    }

    public interface OnDrawerListener{
        /**
         * 抽屜打開關閉過程監聽
         * @param percent 取值區間[0, 1],0代表完全關閉,1代表完全打開
         */
        void onDrawer(float percent);
    }

}

3、Activity中也可以設置手柄的點擊處理:

final HandleDrawerLayout handleDrawerLayout = getActivity().findViewById(R.id.hdl_layout);
		View handleView = getActivity().findViewById(R.id.hdl_handle_view);
		handleView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(handleDrawerLayout.isDrawerOpen()){
                    handleDrawerLayout.closeDrawer();
                }else{
                    handleDrawerLayout.openDrawer();
                }
            }
        });

二、可上下切換,類似縱向的ViewPager,並且上劃時向下彈出菜單效果。以下的註釋會比較少,因爲跟上面的例子類似,所以不過多註釋。看效果圖:

1、佈局文件:

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

    <com.dway.testwork.viewdrag.SlideUpLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="visible">

        <FrameLayout
            android:id="@+id/slide_layout_up"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#1f00ffff">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="up"/>
        </FrameLayout>
        <FrameLayout
            android:id="@+id/slide_layout_down"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#1fffff00">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="down"/>
        </FrameLayout>
        <FrameLayout
            android:id="@+id/slide_layout_slide"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:clickable="true"
            android:background="#1fff00ff">
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:text="slide"/>
        </FrameLayout>

    </com.dway.testwork.viewdrag.SlideUpLayout>

</FrameLayout>
2、SlideUpLayout.java類:

package com.dway.testwork.viewdrag;

import android.content.Context;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

/**
 * 可上下切換,類似縱向的ViewPager,並且上劃時向下彈出菜單效果
 * Created by dway on 2018/1/23.
 */

public class SlideUpLayout extends ViewGroup {

    private View mUpView;
    private View mDownView;
    private View mSlideView;

    private ViewDragHelper mHelper;
    
    //上下滑的程度,0表示在upView,1表示在downView
    private float mSlidePercent = 0;

    private boolean mInLayout = false;
    private boolean mFirstLayout = true;


    public SlideUpLayout(Context context, AttributeSet attrs) {
        super(context, attrs);

        mHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                if(child == mUpView){
                    return Math.max(- mUpView.getMeasuredHeight() + mSlideView.getMeasuredHeight(), Math.min(top, 0));
                }else if(child == mDownView){
                    return Math.max(mSlideView.getMeasuredHeight(), Math.min(top, mUpView.getMeasuredHeight()));
                }else if(child == mSlideView){
                    return Math.max(- mSlideView.getMeasuredHeight(), Math.min(top, 0));
                }
                return 0;
            }

            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mUpView || child == mDownView;
            }

            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                if(releasedChild == mUpView){
                    int upViewHeight = mUpView.getMeasuredHeight();
                    int slideViewHeight = mSlideView.getMeasuredHeight();
                    float offset = (upViewHeight + releasedChild.getTop() - slideViewHeight) * 1.0f / (upViewHeight - slideViewHeight);
                    mHelper.settleCapturedViewAt(releasedChild.getLeft(), yvel > 0 || yvel == 0 && offset > 0.5f ? 0 : -upViewHeight + slideViewHeight);
                    invalidate();
                }else if(releasedChild == mDownView){
                    int downViewHeight = mDownView.getMeasuredHeight();
                    int slideViewHeight = mSlideView.getMeasuredHeight();
                    float offset = (releasedChild.getTop() - slideViewHeight) * 1.0f / downViewHeight;
                    mHelper.settleCapturedViewAt(releasedChild.getLeft(), yvel > 0 || yvel == 0 && offset > 0.5f ? mUpView.getMeasuredHeight() : slideViewHeight);
                    invalidate();
                }
            }

            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                if(changedView == mUpView){
                    mDownView.setTop(top + mUpView.getMeasuredHeight());

                    mSlidePercent = (float) (-top) / mDownView.getMeasuredHeight();
                    if(mSlidePercent > 0.9f){
                        mSlideView.setTop(-mSlideView.getMeasuredHeight() + (int)((mSlidePercent - 0.9f)/(1-0.9) * mSlideView.getMeasuredHeight()));
                    }else{
                        mSlideView.setTop(-mSlideView.getMeasuredHeight());
                    }
                }else if(changedView == mDownView){
                    mUpView.setTop(top - mUpView.getMeasuredHeight());

                    mSlidePercent = (float) (mUpView.getMeasuredHeight() - top) / mDownView.getMeasuredHeight();
                    if(mSlidePercent > 0.9f){
                        mSlideView.setTop(-mSlideView.getMeasuredHeight() + (int)((mSlidePercent - 0.9f)/(1-0.9) * mSlideView.getMeasuredHeight()));
                    }else{
                        mSlideView.setTop(-mSlideView.getMeasuredHeight());
                    }
                }
                requestLayout();
            }

            @Override
            public int getViewVerticalDragRange(View child) {
                return child == mUpView ? mUpView.getMeasuredHeight() - mSlideView.getMeasuredHeight() :
                        child == mDownView ? mDownView.getMeasuredHeight() :
                        child == mSlideView ? mSlideView.getMeasuredHeight() : 0;
            }
        });
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        setMeasuredDimension(widthSize, heightSize);

        mUpView = getChildAt(0);
        mDownView = getChildAt(1);
        mSlideView = getChildAt(2);

        //up
        MarginLayoutParams lp = (MarginLayoutParams) mUpView.getLayoutParams();
        int widthSpec = MeasureSpec.makeMeasureSpec(
                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
        int heightSpec = MeasureSpec.makeMeasureSpec(
                heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY);
        mUpView.measure(widthSpec, heightSpec);

        //slide
        lp = (MarginLayoutParams) mSlideView.getLayoutParams();
        widthSpec = getChildMeasureSpec(widthMeasureSpec,
                lp.leftMargin + lp.rightMargin, lp.width);
        heightSpec = getChildMeasureSpec(heightMeasureSpec,
                lp.topMargin + lp.bottomMargin, lp.height);
        mSlideView.measure(widthSpec, heightSpec);

        //down
        lp = (MarginLayoutParams) mDownView.getLayoutParams();
        widthSpec = MeasureSpec.makeMeasureSpec(
                widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY);
        heightSpec = MeasureSpec.makeMeasureSpec(
                heightSize - lp.topMargin - lp.bottomMargin - mSlideView.getMeasuredHeight(), MeasureSpec.EXACTLY);
        mDownView.measure(widthSpec, heightSpec);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mInLayout = true;
        MarginLayoutParams lp = (MarginLayoutParams) mUpView.getLayoutParams();
        int upTop;
        if(mFirstLayout){
            upTop = lp.topMargin;
        }else{
            upTop = mUpView.getTop();
        }
        mUpView.layout(lp.leftMargin, upTop,
                lp.leftMargin + mUpView.getMeasuredWidth(),
                upTop + mUpView.getMeasuredHeight());

        lp = (MarginLayoutParams) mDownView.getLayoutParams();
        int downTop;
        if(mFirstLayout){
            downTop = mUpView.getMeasuredHeight() + lp.topMargin;
        }else{
            downTop = mDownView.getTop();
        }
        mDownView.layout(lp.leftMargin, downTop,
                lp.leftMargin + mDownView.getMeasuredWidth(),
                downTop + mDownView.getMeasuredHeight());

        lp = (MarginLayoutParams) mSlideView.getLayoutParams();
        int slideTop;
        if(mFirstLayout){
            slideTop = - mSlideView.getMeasuredHeight() + lp.topMargin;
        }else{
            slideTop = mSlideView.getTop();
        }
        mSlideView.layout(lp.leftMargin, slideTop,
                lp.leftMargin + mSlideView.getMeasuredWidth(),
                slideTop + mSlideView.getMeasuredHeight());


        mInLayout = false;
        mFirstLayout = false;
    }


    @Override
    public void requestLayout() {
        if(!mInLayout) {
            super.requestLayout();
        }
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mFirstLayout = true;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mFirstLayout = true;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mHelper.shouldInterceptTouchEvent(ev);
    }


    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        if (mHelper.continueSettling(true)) {
            invalidate();
        }
    }

    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

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

    @Override
    protected LayoutParams generateLayoutParams(LayoutParams p) {
        return new MarginLayoutParams(p);
    }

    public float getSlidePercent(){
        return mSlidePercent;
    }

    public void slideToDown(){
        mHelper.smoothSlideViewTo(mDownView, mDownView.getLeft(), mSlideView.getMeasuredHeight());
        invalidate();
    }

    public void slideToUp(){
        mHelper.smoothSlideViewTo(mUpView, mUpView.getLeft(), 0);
        invalidate();
    }

}
3、Activity中可通過如下方法設置自動切換上下頁面:

SlideUpLayout layout = (SlideUpLayout)findViewById(R.id.slide_layout);
        if(layout.getSlidePercent() == 0) {
            layout.slideToDown();
        }

三、掌握了ViewDragHelper的使用,應該做什麼拖拽之類效果都很輕鬆了

四、這裏面其實還有個事件分派攔截的問題,下一篇文章會繼續講。參考《重寫ViewGroup並藉助ViewDragHelper實現各種拖拽交互效果(二)》,地址 http://blog.csdn.net/lin_dianwei/article/details/79210877









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