ViewDragHelper到底怎么用(一)?

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

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

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

ViewDragHelper到底怎么用(一)?_第1张图片
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

你可能感兴趣的:(ViewDragHelper到底怎么用(一)?)