ViewDragHelper解析

概要

ViewDragHelper是谷歌在2013年的I/O大会上推出的一个用于View拖拽操作的帮助类,借助于该类谷歌同时推出了两个用于侧滑的布局SlidingPaneLayout和DrawerLayout,现在市场上的很多带有侧滑菜单的应用都是基于这两种布局。

ViewDragHelper极大的简化了View的拖拽操作,在它没有出现之前很多侧滑都是采用的第三方库,为了实现侧滑效果需要对touch事件进行自定义拦截和处理,代码量大,实现逻辑也需要很大的耐心才能看懂。如果每个开发人员都从这么原始的步奏开始做起,那对于安卓生态是相当不利的。所以说ViewDragHelper等的出现反映了安卓开发框架已经开始向成熟的方向迈进。

ViewDragHelper使用步骤

ViewDragHelper是作用在一个ViewGroup上,也就是说他不能直接作用到被拖拽的View, 其实这也很好理解,因为View在布局中的位置是父ViewGroup决定的。

如何使用ViewGroup实现一个可以拖动的View?

ViewDragHelper使用大体上可以分为三步来实现:

  1. 创建一个ViewDragHelper实例;
  2. 接管ViewGroup对touch事件的处理;
  3. 自定义ViewDragHelper的回调Callback,处理相关拖拽逻辑。

接下来我们对着三个步骤进行详细的介绍。

步骤一:创建ViewDragHelper实例

创建ViewDragHelper的实例不能直接new,而是使用该类提供的静态方法create方法来创建。

  • forParent 一个ViewGroup, 也就是ViewDragHelper将要用来拖拽谁下面的子View;
  • sensitivity 灵敏度,一般设置为1.0f就行,默认就是1.0,值越大越灵敏;
  • cb 一个回调,用来处理拖拽后的逻辑。

如果在使用过程中对于灵敏度没有特别要求我们直接采用第一个create方法即可。

步骤二:接管touch事件

Android touch事件学习笔记中我们已经介绍过,一般情况下自定义控件处理touch事件都要对两个相关方法进行处理,这两个方法分别是onInterceptTouchEvent和onTouchEvent,它们分别对应事件的拦截和消费机制,当我们引入ViewDragHelper后要接管的就是这两个事件处理方法。当ViewDragHelper接管touch事件之后,我们再也不用担心如何处理ACTION_DOWN、ACTION_UP等繁琐的手势处理方式了。

下面就是对上述两个方法接管处理.

这两个方法就不过多解释了,暂时记住这就是规范,使用ViewDragHelper这两个方法就这样处理,如果深入源码解释代码再来一篇文章才能完全解释清楚吧,不过源码我暂时还没有认真研究,所以解释也就暂时到这里。

步骤三:处理回调

拖拽之后的逻辑处理都在这里了,所以这一步是最重要的一步。接下来我们对个别常用的方法简要介绍一下:

public boolean tryCaptureView(View child, int pointerId)

该方法是抽象方法因此必须被重写,表示尝试捕获子View,如果在ViewGroup中所有的View都可以拖拽,则可以直接返回true,否则可以根据特定条件判断来确定哪些子View是可以拖拽的。

public int clampViewPositionHorizontal(View child, int left, int dx)

表示子child拖拽后在x方向所处位置为left。一般情况下都会重写该方法,然后返回一个left,如果对拖拽位置有特殊限制可以对left进行条件限制,比如不可以拖拽出屏幕等等。相对应得还有一个垂直方向的方法,机制与水平方向类似。

public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy)

每次changedView被拖拽后都会执行的方法,为了兼容低版本的Android系统,一般情况下内部会调用View的一个方法invalidate(),否则在低版本的系统中拖拽changedView时并不会发生位置的改变。既然每次changedView位置改变该方法都会执行,那么这个方法在某些情况下会变得非常有用,如果我们想在自定义控件中添加一些一些事件监听,在该方法中设置监听再好不过了。

public void onViewReleased(View releasedChild, float xvel, float yvel)

该方法当我们手势离开被拖拽releasedChild时执行的方法,就相当于以前我们在ACTION_MOVE或ACTION_CANCEL执行要操作的逻辑一样,当我们松手后需要执行的逻辑都可以在这里处理。

public void onEdgeDragStarted(int edgeFlags, int pointerId)

该方法也非常的有用,特别是在DrawerLayout中,我们知道在边缘拖拽DrawerLayout时会包侧滑菜单拖拽出来实际上就是对该方法的使用,当然了该方法一帮要结合ViewDragHelper一个属性一起使用才有效果,通过设置setEdgeTrackingEnabled(int edgeFlags),edgeFlags有五个选项分别是EDGE_LEFT、EDGE_RIGHT、EDGE_TOP、EDGE_BOTTOM和EDGE_ALL。

public int getViewHorizontalDragRange(View child)

一般方法我们都可以见名释义,可以这里可不是这样了,方法名字字面意思是获取child水平拖拽的范围,可是实际上并不如此,只要返回一个>0的值就可以了,那么为什么还要此方法呢,当我们子child是clickable时,此时如果我们拖拽child,事实上它的位置并不会改变,这时候只要我们重写该方法返回任意一个>0的数字即可。

ViewDragHelper基本示例

ViewDragHelper简单拖拽

vdh01

边缘拖拽

边缘拖拽很简单就在第一个基础上稍微添加一些操作即可,更改后部分代码如下:

vdh02

子View带有clickable属性

该种方式也相当简单,就是在简单拖拽callback回调基础上添加如下两个方法即可。

拖拽之后返回原地点

该方式只有一个难点,就是返回时的执行动画如何操作,我们可以查看DrawerLayout源码,直接copy过来即可使用,网上也有相当多的资源都可以借鉴,当然了既然要返回原地点当然要记住原地点的坐标了。

当然了代码也是在第一个示例基础上添加部分代码即可,添加代码如下:

vdh03

小结

ViewDragHelper的使用的确为我们开发与拖拽相关的布局带来了极大的便利,当然了限于个人能力有限,文中难免有错误疏漏之处,本文只是从应用的角度来简单分析了一下ViewDragHelper,借助于该类我们可以很方面的构造出一个跟QQ消息栏中的侧滑删除栏目一样的效果。当然了随着Google对于Android系统的优化升级,在新的support v7包RecycleView中谷歌已经跟我们提供了官方侧滑删除的示例,不过在那个官方示例中是借助于ItemTouchHelper,这是一个支持RecyclerView滑动删除和拖拽的实用工具类,改天有机会再继续研究一下。

本文地址www.sunnyang.com/358.html

示例源代码下载

参考资料

Android ViewDragHelper源码解析

Viewdraghelper解析

Android ViewDragHelper完全解析 自定义ViewGroup神器

ViewDragHelper详解(一)- 可拖动的view

One comment

发表评论