ViewDragHelper基本方法讲解

来源:互联网 发布:有没有钢琴软件 编辑:程序博客网 时间:2024/06/06 05:47
package com.adnonstop.draghelper.viewgroups;import android.content.Context;import android.support.v4.widget.ViewDragHelper;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.view.ViewTreeObserver;import android.widget.FrameLayout;/** * Created by gzq on 2017/1/19. */public class DragViewGroup extends FrameLayout {    private ViewDragHelper dragHelper;    private View mDragView;    private View mAutoBackView;    private View mEdgeTrackerView;    private int mAutoBackViewOriginalPos_x;    private int mAutoBackViewOriginalPos_y;    public DragViewGroup(Context context) {        this(context, null);    }    public DragViewGroup(Context context, AttributeSet attrs) {        this(context, attrs, 0);    }    public DragViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        dragHelper = ViewDragHelper.create(this, new DragCallback());        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {            @Override            public void onGlobalLayout() {                initChild();            }        });        //拖拽左边界回调        dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);    }    /**     * 在viewGroup绘制初始化过程中,要一个一个添加子view,有多少个子view,就会调用多少次onViewAdded;     * 可以在次做一些view类型判断的工作。     *     * @param child     */    @Override    public void onViewAdded(View child) {        super.onViewAdded(child);//        if (!(child instanceof ViewGroup))//            throw new RuntimeException("the child most be a viewgroup!");    }    /**     * 获取到子view。     */    private void initChild() {        for (int index = 0; index < getChildCount(); index++) {            View child = getChildAt(index);        }    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return dragHelper.shouldInterceptTouchEvent(ev);    }    @Override    public boolean onTouchEvent(MotionEvent event) {        dragHelper.processTouchEvent(event);        return true;    }    @Override    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {        super.onLayout(changed, left, top, right, bottom);        mAutoBackViewOriginalPos_x = mAutoBackView.getLeft();        mAutoBackViewOriginalPos_y = mAutoBackView.getTop();    }    @Override    protected void onFinishInflate() {        super.onFinishInflate();        mDragView = getChildAt(0);        mAutoBackView = getChildAt(1);        mEdgeTrackerView = getChildAt(2);    }    @Override    public void computeScroll() {        if (dragHelper.continueSettling(true)) {            invalidate();        }    }    private class DragCallback extends ViewDragHelper.Callback {        /**         * tryCaptureView 返回ture则表示可以捕获该view,你可以根据传入的第一个参数view决定哪些可以捕获         *         * @param child         * @param pointerId         * @return         */        @Override        public boolean tryCaptureView(View child, int pointerId) {            return true;        }        /**         * @param child         * @param left  对移动的边界进行控制         * @param dx         * @return         */        @Override        public int clampViewPositionHorizontal(View child, int left, int dx) {            int newLeft = Math.max(0, Math.min(left, getWidth() - child.getWidth()));            return newLeft;        }        /**         * @param child         * @param top   控制移动的边界         * @param dy         * @return         */        @Override        public int clampViewPositionVertical(View child, int top, int dy) {            int newTop = Math.max(0, Math.min(top, getHeight() - child.getHeight()));            return newTop;        }        /**         * @param releasedChild         * @param xvel          松手时沿X轴的速度         * @param yvel          松手时沿Y轴的速度         */        @Override        public void onViewReleased(View releasedChild, float xvel, float yvel) {            super.onViewReleased(releasedChild, xvel, yvel);            if (releasedChild == mAutoBackView) {                dragHelper.settleCapturedViewAt(mAutoBackViewOriginalPos_x, mAutoBackViewOriginalPos_y);                invalidate();            }        }        /**         * @param changedView         * @param left        new left         * @param top         new top         * @param dx         * @param dy         */        @Override        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {            super.onViewPositionChanged(changedView, left, top, dx, dy);        }        //        See also:        //                STATE_IDLE 静止        //                STATE_DRAGGING  拖拽中        //                STATE_SETTLING 自动滚动        @Override        public void onViewDragStateChanged(int state) {            super.onViewDragStateChanged(state);        }        /*        * 边界拖动回调:        * 在viewGroup的左边界拖动时的回调。        * */        @Override        public void onEdgeDragStarted(int edgeFlags, int pointerId) {            super.onEdgeDragStarted(edgeFlags, pointerId);            System.out.println("******边界拖动回调**********");        }    }}


点击打开链接



第一个View基本没做任何修改。

第二个View,我们在onLayout之后保存了最开启的位置信息,最主要还是重写了Callback中的onViewReleased,我们在onViewReleased中判断如果是mAutoBackView则调用settleCapturedViewAt回到初始的位置。大家可以看到紧随其后的代码是invalidate();因为其内部使用的是mScroller.startScroll,所以别忘了需要invalidate()以及结合computeScroll方法一起。

第三个View,我们在onEdgeDragStarted回调方法中,主动通过captureChildView对其进行捕获,该方法可以绕过tryCaptureView,所以我们的tryCaptureView虽然并为返回true,但却不影响。注意如果需要使用边界检测需要添加上mDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);


到此,我们已经介绍了Callback中常用的回调方法了,当然还有一些方法没有介绍,接下来我们修改下我们的布局文件,我们把我们的TextView全部加上clickable=true,意思就是子View可以消耗事件。再次运行,你会发现本来可以拖动的View不动了,(如果有拿Button测试的兄弟应该已经发现这个问题了,我希望你看到这了,而不是已经提问了,哈~)。

原因是什么呢?主要是因为,如果子View不消耗事件,那么整个手势(DOWN-MOVE*-UP)都是直接进入onTouchEvent,在onTouchEvent的DOWN的时候就确定了captureView。如果消耗事件,那么就会先走onInterceptTouchEvent方法,判断是否可以捕获,而在判断的过程中会去判断另外两个回调的方法:getViewHorizontalDragRangegetViewVerticalDragRange,只有这两个方法返回大于0的值才能正常的捕获。

所以,如果你用Button测试,或者给TextView添加了clickable = true ,都记得重写下面这两个方法:

@Overridepublic int getViewHorizontalDragRange(View child){     return 1;}@Overridepublic int getViewVerticalDragRange(View child){     return 1;}



0 0