Android拖拽辅助类ViewDragHelper的使用说明

1.先看一下如何构造一个ViewDragHelper:

  
    public static ViewDragHelper create(@NonNull ViewGroup forParent, @NonNull ViewDragHelper.Callback cb) {
        return new ViewDragHelper(forParent.getContext(), forParent, cb);
    }

    public static ViewDragHelper create(@NonNull ViewGroup forParent, float sensitivity, @NonNull ViewDragHelper.Callback cb) {
        ViewDragHelper helper = create(forParent, cb);
        helper.mTouchSlop = (int)((float)helper.mTouchSlop * (1.0F / sensitivity));
        return helper;
    }
    
    
    
    private ViewDragHelper(@NonNull Context context, @NonNull ViewGroup forParent, @NonNull ViewDragHelper.Callback cb) {
                    //获取触发移动的最小距离
            this.mTouchSlop = vc.getScaledTouchSlop();
                        //构造OverScroller
            this.mScroller = new OverScroller(context, sInterpolator);
       
    }

ViewDragHelper的构造是私有的,是通过create()构造对象的。

它有2个create(),第一个传入了parent,也就是使用ViewDragHelper的View本身,第二个是Callback。然后默认调用第二个create(),第二个多了一个参数sensitivity,这个sensitivity是用来设置mTouchSlop的,它值越大mTouchSlop就会越小,就会越敏感,也就是滑动的时候判断move的间距越短。

create()最后调用了构造,可以在构造方法中看到初始化了一个OverScroller,可以判断ViewDragHelper的滑动计算等操作也是通过OverScroller计算的(参考:Android中Scroller的使用及原理解析

2. 再看一下ViewDragHelper的Callback

 public abstract static class Callback {
        public Callback() {
        }
                //View的拖拽状态改变时触发
        //STATE_IDLE: 未被拖拽
        //STATE_DRAGGING:正在被拖拽
        //STATE_SETTLING: 被安放到一个位置中的状态
        public void onViewDragStateChanged(int state) {
        }
                //拖拽时的(开始移动)触发
        //changeView:当前被拖拽的view
        //left:拖动时left坐标
        //top:拖动时top坐标
        //dx:拖拽时x轴偏移量
        //dy:拖拽时y轴偏移量
        public void onViewPositionChanged(@NonNull View changedView, int left, int top, @Px int dx, @Px int dy) {
        }
                //view被捕获时触发(也就是按下)
        //capturedChild:捕获的view
        //activePointerId:按下手指的id,多指触控时会用到
        //一般用于做准备初始化工作
        public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {
        }
                //view被放下时触发
        //releasedChild被放下的view
        //xvel:释放View的x轴方向上的加速度
        //yvel:释放View的y轴方向上的加速度
        //一般用于收尾工作
        public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
        }
                //边缘触摸时触发(需开启边缘触摸)
        //edgeFlags:触摸的位置EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM
            //pointerId: 按下手指的id,多指触控时会用到
        //使用较少,一般不重写
        public void onEdgeTouched(int edgeFlags, int pointerId) {
        }
                //是否开启边缘触摸,true代表开启,默认不开启
        //edgeFlags:触摸的位置EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM
       //使用较少,一般不重写
        public boolean onEdgeLock(int edgeFlags) {
            return false;
        }
                //边缘触摸时触发(需开启边缘触摸)
        //edgeFlags:触摸的位置EDGE_LEFT,EDGE_TOP,EDGE_RIGHT,EDGE_BOTTOM
            //pointerId: 按下手指的id,多指触控时会用到
        //使用较少,一般不重写
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
        }
                //寻找当前触摸点下的子View时会调用此方法,寻找到的View会提供给tryCaptureViewForDrag()来尝试捕获。
        //如果需要改变子View的遍历查询顺序可改写此方法,例如让下层的View优先于上层的View被选中。
        //使用较少,一般不重写
        public int getOrderedChildIndex(int index) {
            return index;
        }
                //暂不明确(返回任何值都可以移动,网上说的都是错的)
       //使用较少,一般不重写
        public int getViewHorizontalDragRange(@NonNull View child) {
            return 0;
        }
                //暂不明确(返回任何值都可以移动,网上说的都是错的)
        //使用较少,一般不重写
        public int getViewVerticalDragRange(@NonNull View child) {
            return 0;
        }
                //尝试捕获被拖拽的view,如果返回true代表可以被拖拽,返回false代表不可以被拖拽
        //var1:被拖拽的view
        //使用时判断需要被拖拽的view是否等等于var1。
        //一般判断很多view其中哪些是否可以移动时使用
        public abstract boolean tryCaptureView(@NonNull View var1, int var2);
                //返回view在水平方向的位置,
        //left:当前被拖拽的的view要移动到的的left值
        //dx:移动的偏移量
        //返回0则无法移动,通常直接返回left
        //一般必须重写此方法返回left
        public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
            return 0;
        }
      
        //返回view在竖直方向的位置,
        //top:当前被拖拽的的view要移动到的的left值
        //dy:移动的偏移量
        //返回0则无法移动,通常直接返回top
        //一般必须重写此方法返回top
        public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
            return 0;
        }
    }

3. ViewDragHelper的使用

  • 先看一下常用到的方法
//以松手前的滑动速度为初速动,让捕获到的View自动滚动到指定位置。只能在Callback的onViewReleased()中调用。
settleCapturedViewAt(int finalLeft, int finalTop)
//以松手前的滑动速度为初速动,让捕获到的View在指定范围内fling。只能在Callback的onViewReleased()中调用。
flingCapturedView(int minLeft, int minTop, int maxLeft, int maxTop)
//指定某个View自动滚动到指定的位置,初速度为0,可在任何地方调用。
smoothSlideViewTo(View child, int finalLeft, int finalTop)
  • 再看使用:
    初始化并重写需要用到的方法:
 viewDragHelper=  ViewDragHelper.create(this, new ViewDragHelper.Callback() {
            @Override
            public boolean tryCaptureView(@NonNull View view, int i) {

                return true;
            }

            @Override
            public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
               return left;
           }

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

           @Override
           public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
               super.onViewReleased(releasedChild, xvel, yvel);
                            super.onViewReleased(releasedChild, xvel, yvel);
                    //让捕获到的View自动滚动到100,300位置,只能在这里使用这个方法
               viewDragHelper.settleCapturedViewAt(100,300);
                 //让捕获到的View在100,100,500,500这个范围内fling  ,只能在这里使用这个方法
               viewDragHelper.flingCapturedView(100,100,500,500);
               //指定某个View自动滚动到500,500,初速度为0,可在任何地方调用。 
               viewDragHelper.smoothSlideViewTo(releasedChild,500,500);
               //以上方法必须手动去刷新页面
                             invalidate();
           }

       });


以上四个为常用的方法,然后获取事件权限:

    @Override
    public boolean onInterceptHoverEvent(MotionEvent event) {
        return viewDragHelper.shouldInterceptTouchEvent(event);
    }

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

    }

之前说了,ViewDragHelper内部是overScroller完成计算的,那么和overScroller一样需要重写computeScroll()一直刷新页面:

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

推荐阅读更多精彩内容

  • 简书个人档案馆23:灵感 作者:安居士/海滨 细心的读者可能会发现,我更文的时间主要集中在凌晨,或者第2天早晨6点...
    海滨公园阅读 168评论 2 4
  • 上周六去香港买奶粉,在深水埗买好了奶粉、洗头精、染发剂......时间还很充裕,就信步逛逛街。 深...
    叶满秋塘阅读 2,275评论 14 24
  • 从一八年高二上学期开学到一九年二十六日,我花了近半年时间看完了一本四百页一百回的书――《西游记》。正常来说,看完应...
    若若星游阅读 192评论 0 0