ViewDragHelper让你处理View拖动时,代码减半!

出处:ViewDragHelper是V4包下的一个文件。java

咱们在自定义ViewGroup的时候,有时候以为很头疼,其中很大一部分缘由就是由于事件处理太麻烦,须要记录大量的成员变量,还有各类判断等等。 
Google也感受到了这个麻烦,因此ViewDragHelper就出现了,ViewDragHelper功能究竟是什么呢?从字面意思上看是View拖拽的帮助类,简而言之就是,在简化View拖拽的时候的代码量。咱们先来看一看到底这个类的帮助有多大? 
先来看一个测拉菜单效果 
这里写图片描述 
先来分析一下,若是咱们不借助这个帮助类实现状况: 
一、重写一个RelativeLayout; 
二、重写其中的onInterceptTouchEvent(作相应的事件拦截操做) 
二、重写其中的onTouchEvent方法(这里面作大量的代码) 
三、定义一个Scroller变量,用来控制手指松开之后的操做 
这里我就不去写代码了,代码量确定很大! 
再来看看借助ViewDragHelper类实现的代码sql

/** * Created by gyzhong on 15/4/8. */ public class VdhLayout01 extends RelativeLayout { private ViewDragHelper mViewDragHelper; private View mCaptureView; private float mInitialMotionX; private float mInitialMotionY; private boolean mIsUnableToDrag; private int mSlideRange; private float mSlideOffset; public VdhLayout01(Context context) { this(context, null); } public VdhLayout01(Context context, AttributeSet attrs) { this(context, attrs, 0); } public VdhLayout01(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context); } private void initView(Context context) { mViewDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCall()); } @Override protected void onFinishInflate() { super.onFinishInflate(); mCaptureView = findViewById(R.id.id_capture_view); TextView textView = (TextView) findViewById(R.id.id_text); textView.setText(Shakespeare.DIALOGUE[0]); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); mCaptureView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { mCaptureView.getViewTreeObserver().removeOnPreDrawListener(this); mSlideRange = mCaptureView.getMeasuredWidth(); return false; } }); } private class DragHelperCall extends ViewDragHelper.Callback { @Override public boolean tryCaptureView(View child, int pointerId) { return child == mCaptureView; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); mSlideOffset = left * 1.0f / mSlideRange*2; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { return clamp(left, 0, mSlideRange / 2); } @Override public int getViewHorizontalDragRange(View child) { return mSlideRange/2; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { int finalLeft; if (xvel > 0 || xvel == 0 && mSlideOffset > .5f) { finalLeft = mSlideRange/2 ; }else { finalLeft = 0 ; } mViewDragHelper.settleCapturedViewAt( finalLeft, mCaptureView.getTop()); invalidate(); } } @Override public void computeScroll() { if (mViewDragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } } private int clamp(int value, int min, int max) { return Math.min(max, Math.max(min, value)); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = MotionEventCompat.getActionMasked(ev); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { mViewDragHelper.cancel(); return false; } if (!isEnabled() || (mIsUnableToDrag && action != MotionEvent.ACTION_DOWN)) { mViewDragHelper.cancel(); return super.onInterceptTouchEvent(ev); } int index = MotionEventCompat.getActionIndex(ev) ; switch (action) { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); mInitialMotionX = x; mInitialMotionY = y; mIsUnableToDrag = false; break; } case MotionEvent.ACTION_MOVE: { final float x = ev.getX(); final float y = ev.getY(); final float adx = Math.abs(x - mInitialMotionX); final float ady = Math.abs(y - mInitialMotionY); int slop = mViewDragHelper.getTouchSlop(); if (adx > slop && adx < ady) { mIsUnableToDrag = true; mViewDragHelper.cancel(); return false; } break; } } return mViewDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { mViewDragHelper.processTouchEvent(event); return true; } }

 

能够看到这里咱们只是处理了事件拦截的操做,由于这里涉及到了ScrollView,若是没有涉及到事件拦截的话,代码量更简单!而最最复杂的onTouchEvent方法,咱们什么都没作,只是让他交给ViewDragHelper类去处理。 
若是看了DrawerLayout和SlidingPaneLayout源码的朋友应该知道,这两个控件就使用了这个帮助类。 
看了ViewDragHelper的使用效果,咱们再来看看它的用法,ide

/** * 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. */

上面那段话是ViewDragHelper类的一个说明。大体意思实说ViewDragHelper是自定义ViewGroup的一个工具类,在咱们对子View拖拽或者复位的时候它提供了一系列有用的操做。 
从这段话中咱们能够知道一个信息,这个类大部分用于自定义ViewGroup中,固然像上面的例子,重写RelativeLayout其实也至关于自定义ViewGroup。 
实例化ViewDragHelper,ViewDragHelper的构造方法私有化了,因此咱们不能直接new,须要经过工具

public static ViewDragHelper create(ViewGroup forParent, float sensitivity, Callback cb) {
        //... return helper; }

post

public static ViewDragHelper create(ViewGroup forParent, Callback cb) { return new ViewDragHelper(forParent.getContext(), forParent, cb); }

 

来实例化,这列有三个参数,分别表明什么意思呢? 
ViewGroup forParent 就是咱们自定义的ViewGroup 
float sensitivity 是一个拖拽的灵敏度 
Callback cb 是ViewDragHelper中定义的一个抽象类,须要咱们在自定义的ViewGroup中重写它,而核心的操做也就在在各种中,了解了这个类中的方法,就基本掌握这个Helper的运用。this

public static abstract class Callback { //但拖拽状态改变的时候会触发这个方法,好比:从一开始不能拖拽,到拖拽 public void onViewDragStateChanged(int state) {} //关键方法:顾名思义,这里就是记录了一些值得变化,可用于咱们处理其余的操做,好比,改变背景颜色 public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} //这个方法不多用到,意义不大,可忽略 public void onViewCaptured(View capturedChild, int activePointerId) {} //关键方法,手指松开会触发这个方法,作复位操做就在此方法中实现 public void onViewReleased(View releasedChild, float xvel, float yvel) {} //当边缘被触摸的时候调用 public void onEdgeTouched(int edgeFlags, int pointerId) {} //边缘设置不可用, public boolean onEdgeLock(int edgeFlags) { return false; } //这个方法也不多用到 public void onEdgeDragStarted(int edgeFlags, int pointerId) {} //给自定义的ViewGroup中的字View 重新排序 public int getOrderedChildIndex(int index) { return index; } //关键方法:设置水平拖动的距离 public int getViewHorizontalDragRange(View child) { return 0; } //关键方法:设置垂直拖动的距离 0 表示不可拖动 public int getViewVerticalDragRange(View child) { return 0; } //关键方法:返回true表示能够拖动 public abstract boolean tryCaptureView(View child, int pointerId); //关键方法:从新定位水平移动的位置,返回left表示不受限制 public int clampViewPositionHorizontal(View child, int left, int dx) { return 0; } //关键方法:从新定位垂直移动的位置,返回top表示不受限制 public int clampViewPositionVertical(View child, int top, int dy) { return 0; } }

看了以上注释,再回过头来看上面的例子是否是以为很简单。spa

总结:.net

一、ViewDragHelper的做用是一个简化View拖动的帮助类 
二、ViewDragHelper大部分用在自定义ViewGroup中 
三、ViewDragHelper的实例化经过code

create(ViewGroup forParent, float sensitivity, Callback cb) 

方法建立 
四、在自定义的ViewGroup中的onInterceptTouchEvent方法中别忘记调用ViewDragHelper中的shouldInterceptTouchEvent(ev), 
同理onTouchEvent(MotionEvent event)中须要调用 
ViewDragHelper.processTouchEvent(event);server

源码下载

http://blog.csdn.net/jxxfzgy/article/details/44954705

相关文章
相关标签/搜索