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>

代码下载:下载

 

posted @ 2015-05-18 18:11  perfect亮  阅读(1129)  评论(0)    收藏  举报