ViewDragHelper详解(一)

来源:互联网 发布:网络侦探 艾可萨兽 编辑:程序博客网 时间:2024/05/03 04:46

一、ViewDragHelper是什么

看到这个类,我们首先应该想到它是什么?

从字面意思中我们可以大概猜到了一点。那么它具体是做什么的呢?官方文档对这个类进行了简单的阐述:

ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to drag and reposition views within their parent ViewGroup.

ViewDragHelper是一个实用的类,用来开发自定义ViewGroup。它定义了一组有用的操作和状态追踪,允许用户在父ViewGroup中拖动并且重新定位子View(child view)。

从官方的介绍中我们了解到了几个关键点:

  1. 自定义ViewGroup
  2. 拖动以及重新定位
  3. 操作和状态追踪

二、ViewHelper的看的见的地方有哪些?

当我们看到一个未知的东西,我们的心里总是充满疑惑,想要探究一下可以看得见和摸得着的感知。 在我的系列文章中也将会给大家奉献看得见的GIF,将相关函数和具体表现形象的展示出来。

  1. DrawerLayout
  2. QQ5.0以上的侧滑效果

三、 从实例来讲解ViewDragHelper

我们将会看到常用函数的用法

步骤一: 创建我们自定义的LinearLayout

public class VDHLinearLayout extends LinearLayout {    private ViewDragHelper mViewDragHelper = null;    public VDHLinearLayout(Context context, AttributeSet attrs) {        super(context, attrs);        createVDH(null);    }    public void createVDH(ViewDragHelper.Callback callback) {        if (callback == null) {            mViewDragHelper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {                @Override                public boolean tryCaptureView(View child, int pointerId) {                    return true;                }            });        } else {            mViewDragHelper = ViewDragHelper.create(this, 1.0f, callback);        }    }      @Override    public boolean onTouchEvent(MotionEvent event) {        if (mViewDragHelper == null) {            return super.dispatchTouchEvent(event);        }        mViewDragHelper.processTouchEvent(event);        return true;    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        if (mViewDragHelper == null) {            return super.onInterceptTouchEvent(ev);        }        int keyCode = ev.getAction();        if (keyCode == MotionEvent.ACTION_CANCEL) {            mViewDragHelper.cancel();            return false;        }        return mViewDragHelper.shouldInterceptTouchEvent(ev);    }    public ViewDragHelper getViewDragHelper() {        return mViewDragHelper;    }}

步骤二:创建布局文件activity_main.xml

<?xml version="1.0" encoding="utf-8"?><com.demonli.vdh.view.VDHLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fitsSystemWindows="true"    android:orientation="vertical"    tools:context="com.demonli.vdh.MainActivity"    android:id="@+id/root_vdh"    android:paddingTop="10dp"    android:paddingBottom="30dp"    android:paddingLeft="15dp"     android:paddingRight="20dp"    >    <TextView        android:id="@+id/child1"        android:layout_margin="10dp"        android:gravity="center"        android:layout_gravity="center"        android:background="@color/colorPrimary"        android:text="CommonDragView"        android:layout_width="100dp"        android:layout_height="100dp"/>    <TextView        android:id="@+id/child2"        android:layout_margin="10dp"        android:layout_gravity="center"        android:gravity="center"        android:background="@color/colorAccent"        android:text="AutobackView"        android:layout_width="100dp"        android:layout_height="100dp"/>    <TextView        android:id="@+id/child3"        android:layout_margin="10dp"        android:layout_gravity="center"        android:gravity="center"        android:background="@android:color/holo_red_dark"        android:text="EdgeTrackerView"        android:layout_width="100dp"        android:layout_height="100dp"/></com.demonli.vdh.view.VDHLinearLayout>

步骤三:创建MainActivity

public class MainActivity extends AppCompatActivity {    private VDHLinearLayout mVDHLiearLayout;    private TextView mDragView;    private TextView mAutobackView;    private TextView mEdgeView;    Point mAutobackPoint = new Point();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mDragView = (TextView) findViewById(R.id.child1);        mAutobackView = (TextView) findViewById(R.id.child2);        mEdgeView = (TextView) findViewById(R.id.child3);        mVDHLiearLayout = (VDHLinearLayout) findViewById(R.id.root_vdh);        init();    }    protected void init() {        mVDHLiearLayout.createVDH(new VDHCallback());        mAutobackView.postDelayed(new Runnable() {            @Override            public void run() {                mAutobackPoint.set(mAutobackView.getLeft(), mAutobackView.getTop());            }        }, 0);    }    class VDHCallback extends ViewDragHelper.Callback {        /**         * 此例中 mEdgeView将无法被拖动         * 此函数必须实现         *         * @param child         * @param pointerId         * @return if false,那么child view将无法拖动(Drag)         */        @Override        public boolean tryCaptureView(View child, int pointerId) {            if (child == mEdgeView) {//                return false;            }            return true;        }        /**         * 实现对child view x 轴方向的控制         *         * @param child         * @param left         * @param dx         * @return         */        @Override        public int clampViewPositionHorizontal(View child, int left, int dx) {            int leftBound = mVDHLiearLayout.getPaddingLeft();            int rightBound = mVDHLiearLayout.getWidth() - mVDHLiearLayout.getPaddingRight() - child.getWidth();//                if(left<leftBound){//                    left = leftBound;//                }else if(left>rightBound){//                    left = rightBound;//                }            //更加简洁的写法            left = Math.min(Math.max(left, leftBound), rightBound);            return left;        }        /**         * 对child view y 轴方向的控制         *         * @param child         * @param top         * @param dy         * @return         */        @Override        public int clampViewPositionVertical(View child, int top, int dy) {            int topBound = mVDHLiearLayout.getPaddingTop();            int bottomBound = mVDHLiearLayout.getHeight() - child.getHeight() - mVDHLiearLayout.getPaddingBottom();            if (top < topBound) {                top = topBound;            } else if (top > bottomBound) {                top = bottomBound;            }            return top;        }    }}

经过步骤一、二、三之后我们可以看到以下的效果:
这里写图片描述

我们会发现:
1、mDragView和mAutobackView可以Drag,而mEdgeView没有移动。
2、同时我们会主要到mDragView和mAutobackView无法到达屏幕的边界。

1、tryCaptureView( ) :试图捕获child view的drag 事件,如果指定子view 返回false,则会出现像mEdgeView那样无法Drag的情况。
2、布局文件activity_main.xml中我们定义根布局中的paddingLeft等,并且在MainActivity中实现了clampViewPositionVertical()与clampViewPositionHorizontal()两个函数。函数的具体意义见代码中的注释。

步骤四:实现mAutobackView的拖动后自动返回到原来的位置:

在VDHLinearLayout中添加:

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

在MainActivty中添加:

 @Override        public void onViewReleased(View releasedChild, float xvel, float yvel) {            if(releasedChild==mAutobackView){                mVDHLiearLayout.getViewDragHelper().settleCapturedViewAt(mAutobackPoint.x,mAutobackPoint.y);                mVDHLiearLayout.invalidate();            }        }

接下来我们会看到这样的效果:
这里写图片描述

我们可以看出来mAutobackView自动的回到原来的位置。

1、首先我们保存了mAutobackView的初始坐标

mAutobackView.postDelayed(new Runnable() {            @Override            public void run() {                mAutobackPoint.set(mAutobackView.getLeft(), mAutobackView.getTop());            }        }, 0);

然后我们在VDHCallback实现了:

 /**         * 此函数用于捕捉用户的ACTION_UP         * @param releasedChild         * @param xvel         * @param yvel         */        @Override        public void onViewReleased(View releasedChild, float xvel, float yvel) {            if(releasedChild==mAutobackView){                mVDHLiearLayout.getViewDragHelper().settleCapturedViewAt(mAutobackPoint.x,mAutobackPoint.y);                mVDHLiearLayout.invalidate();            }        }

步骤五:实现mEdgeView从屏幕边界滑动时的移动效果

 @Override        public void onEdgeDragStarted(int edgeFlags, int pointerId) {            // super.onEdgeDragStarted(edgeFlags, pointerId);            mVDHView.getViewDragHelper().captureChildView(mEageView, pointerId);        }
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_ALL);

这里写图片描述

这样我们的mEdgeView便可拖动了。

对于ViewDragHelper.Callback中没有讲到的方法如下:

onViewDragStateChanged()
当ViewDragHelper状态发生变化时回调(IDLE,DRAGGING,SETTING[自动滚动时])

onViewPositionChanged
当captureview的位置发生改变时回调

onViewCaptured()
当captureview被捕获时回调

onEdgeTouched()
当触摸到边界时回调。

onEdgeLock()
true的时候会锁住当前的边界,false则unLock。

getOrderedChildIndex()
改变同一个坐标(x,y)去寻找captureView位置的方法。(具体在:findTopChildUnder方法中)

0 0
原创粉丝点击