ViewDragHelper仿美团订单拖拽功能 初探

来源:互联网 发布:java object notify 编辑:程序博客网 时间:2024/06/04 19:42

对于ViewDragHelper其强大的功能,想必有很多人都很了解了。例如我们的“侧滑”菜单功能drawerLayout 就是用ViewDragHelper做的。还有就是我们今天要做的仿美团的订单。先看图:

爱吃美团的应该就知道,有这个界面。我也是最近才发现的,因为公司这边吃饭不方便,哎!先看我们后期做成的效果图:

                                    

感觉还挺.....可以的。

下面就来看看具体是怎么实现的,当然我们首先要看一看ViewDragHelper这个类是怎么使用的,有哪些参数。

顾名思义ViewDragHelper = view + drag + help 翻译一下就是 “帮助”  “拖拽”  “视图”英语不好才四级个人理解。

ViewDragHelper和我们比较熟悉的GestureDetector 这个类用法有点相似。对于GestureDetector我们比较熟悉,要使用它首先就是要有ontouchevent 和onInterceptTouchevent 这两个事件。ViewDragHelper 也不例外也要实现这两个方法。GestureDetector的手势实现是通过接口回调不同的手势操作,有单击,双击,滑动等。对于viewdraghelper 它是通过oncreat()方法创建对象的,不是new的。下面就介绍一下具体使用的方法来实现一个简单的图片拖拽:


第一步:创建ViewDragHelper对象

 

ViewDragHelper dragHelper = ViewDragHelper.create( this , 1.0f , Callback);

下面对create()中的参数讲解一下,第一个参数就是当前的ViewGroup对象,第二个参数是手势拖拽的敏感系数,系数越大越敏感,第三个参数也是最重要的 接口了。所有拖拽的操作都是通过这个接口来实现的。


第二步:CallBack 接口中的所有方法的介绍和讲解,这里主要是先介绍每个方法的作用,后面我们在结合例子使用举例。


             方法一:

@Overridepublic boolean tryCaptureView(View child, int pointerId) {    return false;}

 这个方法是判断当前哪一个 view 可以拖动,false 是所有都不支持拖动,为true的时候是支持拖动,这里一般我们根据 child 判断当前是哪一个view 是否支持 拖动,支持就返回 true,否则就返回false。

    方法二:

@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {    return super.clampViewPositionHorizontal(child, left, dx);}
这个方法是水平位置拖拽,child 是拖拽的对象,left是 view 距离左边的距离,这里如果 return 返回的是 left 那么view的位置左边距就是left。设置这个方法,view 就可以水平 拖拽。

         方法三:

@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {    return super.clampViewPositionVertical(child, top, dy);}

这个方法和上面的方法是想同的,垂直位置拖拽,child 是拖拽的对象,top是 view 距离顶部的距离,这里如果 return 返回的是 top那么view的位置顶边距就是top。设置这个方法view就可以垂直拖拽。

方法四:

@Overridepublic int getViewHorizontalDragRange(View child) {    return super.getViewHorizontalDragRange(child);}
其实看了这么多方法,大家看方法名字也知道,这个方法翻译就是水平拖拽的范围,所以这里如果return 返回参数那就要返回当前view水平水平拖拽在屏幕中的范围。

方法五:

@Overridepublic int getViewVerticalDragRange(View child) {    return super.getViewVerticalDragRange(child);}
和最前面的两个方法一样这个方法和第四个方法配合使用,就是如果我们设置了水平方向的拖拽范围,同理也要设置垂直方向上的拖拽范围,不然不起作用。如果你想 禁止 水平或者 垂直方向的拖动,那可一直接返回 0 。

方法六:

@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel) {    super.onViewReleased(releasedChild, xvel, yvel);}
这个方法 view release 翻译就是 view 释放的时候,就是我们手指 拖拽 view 然后手指 松开后调用的方法,他的参数要好好的说一下了,第一个参数 releasedChild 就是我们拖动的view对象,这个很好理解,重要的是后面两个,xvel这个参数是水平滑动的 速率,yvel 这个是垂直方向的速率,这也都好区分因为前面有x 和 y。但是要注意:的是 这两个 速率 都是有 正 负值的,这个正负值对我们来说 是很重要的,我们可以通过 这个正负值 来判断当前 手指 滑动的方向。正直 =》 就是x 或 y方向的正 方向。负值 =》就是 x或y的负方向。

方法七:

@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {    super.onViewPositionChanged(changedView, left, top, dx, dy);}
这个方法当view 位置 发生改变时 调用,就是我们在拖拽的时候 一直在调用这个方法,这个方法 中的 left 和 top 就是当前view 所距离屏幕左侧和顶部的距离。在这个方法中我们可以处理一些 view 的 动画比如 :缩放,移动,旋转等。

其他还有一些方法,就不一一介绍了,基本你会使用上面的这 7 个方法 就可以做出 很炫的界面了。其他方法边缘 检测了。


第三步; 说了这么多,下面我们就来写一个简单的例子,过度一下

使用到的都是我们上面讲过的方法:具体代码里面有注释,主要就是通过一个例子来帮我们练练手,熟悉每个方法的具体用法。

public class ViewDraghelperDemo extends FrameLayout {    ViewDragHelper dragHelper ;    public ViewDraghelperDemo(@NonNull Context context) {        this(context,null);    }    public ViewDraghelperDemo(@NonNull Context context, @Nullable AttributeSet attrs) {        this(context,attrs,0);    }    public ViewDraghelperDemo(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {        super(context, attrs, defStyleAttr);        dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {            @Override            public boolean tryCaptureView(View child, int pointerId) {                return true;            }            @Override            public int clampViewPositionHorizontal(View child, int left, int dx) {                //取得左边界的坐标                final int leftBound = getPaddingLeft();                //取得右边界的坐标                final int rightBound = getWidth() - child.getWidth() - leftBound;                //这个地方的含义就是 如果left的值 在leftboundrightBound之间 那么就返回left                //如果left的值 比 leftbound还要小 那么就说明 超过了左边界 那我们只能返回给他左边界的值                //如果left的值 比rightbound还要大 那么就说明 超过了右边界,那我们只能返回给他右边界的值                return Math.min(Math.max(left, leftBound), rightBound);            }            //同上            @Override            public int clampViewPositionVertical(View child, int top, int dy) {                final int topBound = getPaddingTop();                final int bottomBound = getHeight() - child.getHeight() - topBound;                return Math.min(Math.max(top, topBound), bottomBound);            }            @Override            public int getViewHorizontalDragRange(View child) {                //计算水平拖拽范围,让view 在屏幕内 拖拽                if (child==mn){                    return getWidth()-getPaddingLeft()-child.getWidth();                }                return super.getViewHorizontalDragRange(child);            }            @Override            public int getViewVerticalDragRange(View child) {                //计算垂直拖拽范围,让view 在屏幕内 拖拽                if (child == mn){                    return getHeight() - getTop() - child.getHeight();                }                return super.getViewVerticalDragRange(child);            }        });    }    ImageView mn;    /**     * 布局加载完成后,运行这个方法,可以在这个方法中初始化一些 对象view     */    @Override    protected void onFinishInflate() {        super.onFinishInflate();        mn = (ImageView) this.findViewById(R.id.mn);    }    /**     * 下面这两个方法必须要增加,接管手势的     * @param event     * @return     */    @Override    public boolean onTouchEvent(MotionEvent event) {        dragHelper.processTouchEvent(event);        return true;    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return dragHelper.shouldInterceptTouchEvent(ev);    }}
这个是一个图片拖拽的例子,是不是很简单就实现了,如果我们用手势来做的话 ,我们要时刻 获取当前的x和y坐标,但是用viewdraghelper就不用。下面一片就具体和大家探讨一下 美团的 布局上推 下拉 滚动的。写在一起,太长了,看起来很枯燥,所以大家谅解一下。