android 拖拽帮助类ViewDragHelper
ViewDragHelper
1.前言
在做android的View拖拽的时候,往往要用到dispatchTouchEvent , onInterceptTouchEvent , onTouchEvent,而且还要在这些方法中去实现比较复杂的逻辑,
如果和ViewGroup相关的话,多个子View拖拽,还可能产生事件冲突,这些问题是相当麻烦的。所以Google应运而生就出现了ViewGragHelper.
2.ViewGragHelper介绍:
从官方文档来看:ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to drag and reposition views within their parent ViewGroup
这句话中要注意两点:
- ViewdDragHelper 必须作用于ViewGroup上 , 必进子View的位置还是由父View来决定的
- ViewdDragHelper 给我们提供了大量有用操作来跟踪用户对View的拖拽
3.简单实现一个拖拽效果的步骤:
- 在ViewGroup中通过工厂方法实例化ViewdDragHelper。
ViewDragHelper.create(ViewGroup forParent, float sensitivity, ViewDragHelper.Callback cb);
ViewGroup forParent :即你要拖动哪个ViewGroup下面的子View
float sensitivity : 灵敏度 默认为1.0即可
ViewDragHelper.Callback cb : 处理拖动位置的回调
- 继承ViewDragHelper.Callback类,该类有个抽象方法:tryCaptureView(View view, int pointerId) 表示尝试捕获子view,这里一定要返回true, 返回true表示允许
- 重写两个方法int clampViewPositionHorizontal(View child, int left, int dx)和int clampViewPositionHorizontal(View child, int left, int dx) 这两个方法分别用来处理x方向和y方向的拖动的,返回值该child现在的位置。
- 重写ViewGroup的onInterceptTouchEvent(MotionEvent ev)用来拦截事件
- 重写ViewGroup的onTouchEvent(MotionEvent event) 在这里面只要做两件事:mDragHelper.processTouchEvent(event);处理拦截到的事件,这个方法会在返回前分发事 件;return true 表示 消费了事件。
- 简单的5步就可以实现一个可以任意拖动到view了,当然我们需要在clampViewPositionHorizontal和clampViewPositionVertical中做一点工作,以防止view超出了边界。
4.下面通过代码简单实现一个拖拽
1 public class CustomView extends LinearLayout { 2 3 private ViewDragHelper dragHelper; 4 5 public CustomView(Context context) { 6 this(context, null); 7 } 8 9 public CustomView(Context context, AttributeSet attrs) { 10 this(context, attrs, 0); 11 } 12 13 public CustomView(Context context, AttributeSet attrs, int defStyle) { 14 super(context, attrs, defStyle); 15 init(); 16 } 17 18 private void init() { 19 setOrientation(LinearLayout.VERTICAL); 20 dragHelper = ViewDragHelper.create(this, (float) 1.0, 21 new ViewDragHelper.Callback() { 22 23 // 尝试捕获要拖动的子View 这里一定要返回true 24 @Override 25 public boolean tryCaptureView(View view, int pointerId) { 26 27 28 return true; 29 } 30 31 /** 32 * 处理水平方向上的拖动 33 * 34 * @param View 35 * child 被拖动到view 36 * @param int left 移动到达的x轴的距离 37 * @param int dx 建议的移动的x距离 38 */ 39 @Override 40 public int clampViewPositionHorizontal(View child, 41 int left, int dx) { 42 43 //拖动子View时候,限制拖动的边界位置 44 45 if (getPaddingLeft() > left) { 46 return getPaddingLeft(); 47 } 48 if (left > (getWidth() - getPaddingLeft() 49 - getPaddingRight() - child.getWidth()) 50 + getPaddingLeft()) { 51 return (getWidth() - getPaddingLeft() 52 - getPaddingRight() - child.getWidth()) 53 + getPaddingLeft(); 54 } 55 56 if (getWidth() - child.getWidth() < left) { 57 return getWidth() - child.getWidth(); 58 } 59 return left; 60 } 61 62 @Override 63 public int clampViewPositionVertical(View child, int top, 64 int dy) { 65 66 if (getPaddingTop() > top) { 67 return getPaddingTop(); 68 } 69 70 if (getHeight() - child.getHeight() < top) { 71 return getHeight() - child.getHeight(); 72 } 73 74 return top; 75 } 76 77 /** 78 * 当拖拽到状态改变时回调 79 * 80 * @params 新的状态 81 */ 82 @Override 83 public void onViewDragStateChanged(int state) { 84 switch (state) { 85 // 正在被拖拽 86 case ViewDragHelper.STATE_DRAGGING: 87 break; 88 // view没有被拖拽或者正在进行fling 89 case ViewDragHelper.STATE_IDLE: 90 break; 91 // fling完毕后被放置到一个位置 92 case ViewDragHelper.STATE_SETTLING: 93 break; 94 } 95 96 super.onViewDragStateChanged(state); 97 } 98 99 }); 100 101 } 102 103 @Override 104 public boolean dispatchTouchEvent(MotionEvent ev) { 105 return super.dispatchTouchEvent(ev); 106 } 107 108 @Override 109 public boolean onInterceptTouchEvent(MotionEvent ev) { 110 111 switch (ev.getAction()) { 112 case MotionEvent.ACTION_CANCEL: 113 break; 114 case MotionEvent.ACTION_DOWN: 115 dragHelper.cancel(); 116 break; 117 } 118 /** 119 * 检查是否可以拦截touch事件 如果onInterceptTouchEvent可以return true 则这里return true 120 */ 121 return dragHelper.shouldInterceptTouchEvent(ev); 122 } 123 124 @Override 125 public boolean onTouchEvent(MotionEvent event) { 126 /** 127 * 处理拦截到的事件 这个方法会在返回前分发事件 128 */ 129 dragHelper.processTouchEvent(event); 130 131 return true; 132 } 133 134 }
XML文件:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:paddingBottom="@dimen/activity_vertical_margin" 6 android:paddingLeft="@dimen/activity_horizontal_margin" 7 android:paddingRight="@dimen/activity_horizontal_margin" 8 android:paddingTop="@dimen/activity_vertical_margin" 9 tools:context=".MainActivity" > 10 11 <com.example.dragviewhelpertest.view.CustomView 12 android:layout_width="match_parent" 13 android:layout_height="match_parent" 14 android:paddingLeft="100dp" 15 android:paddingRight="100dp" > 16 17 <TextView 18 android:layout_width="100dp" 19 android:layout_height="100dp" 20 android:background="#FFFF0000" /> 21 22 </com.example.dragviewhelpertest.view.CustomView> 23 24 </RelativeLayout>

代码下载:下载

浙公网安备 33010602011771号