ViewDragHelper到底怎么用(一)?

开发中,我们经常会有拖动View的一些效果,比如

  • 1.跟着手指移动的小球
  • 2.抽屉效果
  • 3.手指拨动后就返回上一个页面的效果

这些效果如果完全靠自己自定义ViewGroup,然后重写onTouchEvent以及onInterceptTouchEvent来完成会非常的麻烦,挑战性很大。但是假如有了ViewGragHelper的帮助,会变得简单很多。所以,可以看到ViewDragHelper一般出现在自定义ViewGroup中,帮助我们快速的处理一些手势相关的效果。
先上图看这个例子:

image.png
  • 第一个View,就是演示简单的移动
  • 第二个View,演示除了移动后,松手自动返回到原本的位置。(注意你拖动的越快,返回的越快)
  • 第三个View,边界移动时对View进行捕获。

实现步骤

1.自定义ViewGroup,继承LinearLayout

public class VDHLayout extends LinearLayout

2.在构造方法中创建ViewGragHelper对象,同时设置屏幕左边缘可以被追踪:

mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            .... //这里面会覆写很多方法
            ....//这里面会覆写很多方法
            ....//这里面会覆写很多方法
            ....//这里面会覆写很多方法
        });
mDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

这里的第二参数是1.0f代表sensitivity, 主要用于设置touchslop

3.要想把一系列的事件交给ViewDragHelper处理的话,需要重写以下方法:

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
   return mDragger.shouldInterceptTouchEvent(event);
}

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

4.这一步就是要override callback方法,来实现对ViewGroup下的子View的控制。

4.1获取子View的对象
@Override
 protected void onFinishInflate() {
      super.onFinishInflate();
      mDragView = getChildAt(0);
      mAutoBackView = getChildAt(1);
     mEdgeTrackerView = getChildAt(2);
 }
4.2由于第二个View当被拖动以后需要回到原来的位置,所以需要记录当前的位置, 覆写onLayout方法
private Point mAutoBackOriginPos = new Point();
@Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        mAutoBackOriginPos.x = mAutoBackView.getLeft();
        mAutoBackOriginPos.y = mAutoBackView.getTop();
    }
4.3由于第三个View在手指触摸它的时候不会移动,所以
@Override
 public boolean tryCaptureView(View child, int pointerId) {
                //mEdgeTrackerView禁止直接移动
                return child == mDragView || child == mAutoBackView;
}

也就是需要触发touch事件的view需要覆写这个方法,并且要指定childview

4.4手指释放后,弹回原来的位置
//手指释放的时候回调
 @Override
 public void onViewReleased(View releasedChild, float xvel, float yvel) {
         //mAutoBackView手指释放时可以自动回去
         if (releasedChild == mAutoBackView) {
               mDragger.settleCapturedViewAt(mAutoBackOriginPos.x, mAutoBackOriginPos.y);
               invalidate();
         }
 }

注意由于这里使用的是invalidate方法,所以需要重写

  @Override
   public void computeScroll() {
       if (mDragger.continueSettling(true)) {
           invalidate();
       }
   }
4.5指定边界能拖动的View
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
      mDragger.captureChildView(mEdgeTrackerView, pointerId);
}
4.6当想要控制View的移动边界的时候,可以:
           @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                //只在ViewGroup的内部移动
                final int leftBound = getPaddingLeft();
                final int rightBound = getWidth() - child.getWidth() - getPaddingRight();
                //这个写法不懂
                //我希望只在ViewGroup的内部移动,
                // 即:最小>=paddingleft,最大<=ViewGroup.getWidth()-paddingright-child.getWidth。
                final int newLeft = Math.min(Math.max(left, leftBound), rightBound);

                return newLeft;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                return top;
            }

到此,我们列一下所有的Callback方法,看看还有哪些没用过的:

  • onViewDragStateChanged

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

  • onViewPositionChanged

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

  • onViewCaptured

当captureview被捕获时回调
onViewReleased 已用

  • onEdgeTouched

当触摸到边界时回调。

  • onEdgeLock

true的时候会锁住当前的边界,false则unLock。
onEdgeDragStarted 已用

  • getOrderedChildIndex

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

getViewVerticalDragRange 已用
tryCaptureView 已用
clampViewPositionHorizontal 已用
clampViewPositionVertical 已用
ok,至此所有的回调方法都有了一定的认识。

5.项目源码
源码参考我的github地址

参考文章:

http://blog.csdn.net/lmj623565791/article/details/46858663

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容