ViewDragHelper是一个V4包下的类, 可以帮助实现对子View的滑动拖放需求. 通常定义在自定义ViewGroup的内部
参考
ViewDragHelper 的基本使用
常用Api
初始化
1
| public static ViewDragHelper create(@NonNull ViewGroup forParent, @NonNull ViewDragHelper.Callback cb)
|
第一个参数是父布局, 第二个参数是自定义的监听回调
拦截事件
在自定义的ViewGroup中需要将点击事件交给ViewDragHelper来判断
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mViewDragHelper.shouldInterceptTouchEvent(ev); }
@Override public boolean onTouchEvent(MotionEvent event) { mViewDragHelper.processTouchEvent(event); return true; }
|
处理computeScroll
因为ViewDragHelper内部是通过Scroller来实现的, 所以要重写computeScroll方法(当Scroller处理滑动时, 会调用computeScroll方法)
1 2 3 4 5 6 7
| @Override public void computeScroll() { super.computeScroll(); if (mViewDragHelper != null && mViewDragHelper.continueSettling(true)){ invalidate(); } }
|
处理CallBack回调
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| private ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
@Override public boolean tryCaptureView(View child, int pointerId) { }
@Override public int clampViewPositionHorizontal(View child, int left, int dx) { }
@Override public int clampViewPositionVertical(View child, int top, int dy) { }
@Override public void onViewReleased(View releasedChild, float xvel, float yvel) { } };
|
ViewDragHelper.Callback 是一个抽象类, 有很多可以重写的方法, 上面的是常用的方法
还有一些常用的关于边缘滑动相关的重写方法
在这里就不写了
例子
实现一个支持拖拽, 有粘性的ViewGroup
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| public class DragLayout extends LinearLayout {
private float mRaftValue = UIUtils.dip2Px(getContext(), 20);
private float mRaftYVel = 1000.0f;
private ViewDragHelper mDragHelper;
private OnDismissListener mOnDismissListener;
private boolean mDragToggle = true;
public DragLayout(@NonNull Context context) { this(context, null); }
public DragLayout(@NonNull Context context, @Nullable AttributeSet attrs) { this(context, attrs, 0); }
public DragLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); }
public void setOnDismissListener(OnDismissListener onDismissListener) { mOnDismissListener = onDismissListener; }
private void init() { ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { private int mCurrentTop;
@Override public boolean tryCaptureView(@NonNull View child, int pointerId) { return mDragToggle; }
@Override public int clampViewPositionVertical(@NonNull View child, int top, int dy) { if (top < 0) { top = 0; } mCurrentTop = top; return top; }
@Override public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (mCurrentTop <= mRaftValue && yvel <= mRaftYVel) { mDragHelper.settleCapturedViewAt(0, 0); invalidate(); } else { if (mOnDismissListener != null) { mOnDismissListener.onDismiss(); } } }
@Override public int getViewVerticalDragRange(@NonNull View child) { return 1; } };
mDragHelper = ViewDragHelper.create(this, callback);
}
@Override public boolean dispatchTouchEvent(MotionEvent ev) { return super.dispatchTouchEvent(ev); }
@Override public boolean onInterceptTouchEvent(MotionEvent ev) {
return mDragHelper.shouldInterceptTouchEvent(ev); }
@Override public boolean onTouchEvent(MotionEvent event) { try { mDragHelper.processTouchEvent(event); } catch (Exception e) { e.printStackTrace(); } return true; }
@Override public void computeScroll() { if (mDragHelper != null && mDragHelper.continueSettling(true)) { invalidate(); } }
public interface OnDismissListener { void onDismiss(); } }
|
注意 在xml布局中, DragLayout必须只有一个直接子View, 这样才能实现对所有内容的拖拽