从源码角度分析ViewDragHelper
2016-11-26 16:25
513 查看
最近群里的小伙伴都在说ViewDragHelper这玩意,我就感觉好像很牛逼的样子。然后稍微看了下,不是很难,在此先做个笔记。因为之前他们说scroller的时候,我都不知道是啥。然后今天发现我去年写的demo中还用到了。原谅我猪一般的记性!!
先来个测试demo的效果图。
下面直接上代码:
好了,回归整体,从源码角度开始分析,接下来要放大招了~~~
ViewDragHelper并不强大,强大的是他有一个回调函数
我们点开ViewDragHelper的源码,找到他的回调:
接下来,我们分析一下他们分别是什么时候才会调用的。
onViewDragStateChanged
onViewPositionChanged
onViewCaptured
onViewReleased
onEdgeTouched
onEdgeLock
onEdgeDragStarted
getOrderedChildIndex
getViewHorizontalDragRange
getViewVerticalDragRange
tryCaptureView
clampViewPositionHorizontal
clampViewPositionVertical
到这边,应该所有的方法都介绍完了。好了,现在我们来聊聊,ViewDragHelper的方法。
创建一个ViewDragHelper对象
至于有小伙伴对sensitivity这个属性有疑问,那么我们点开源码来了解下他是干嘛的。
我们传入的值越大,他的值越小。但mTochSlop是怎么计算的呢,我们继续看源码:
我们定位到了这个:vc.getScaledTouchSlop();这个属性是用来干嘛的呢。我查了下。解释如下:
getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件。
现在不要我多说了把。就是你一次最少滑动的距离要大于这个距离,否则,视图是不会移动了。
好了,现在看我们之前的demo还用到了什么。
继续看源码:
等于1是什么鬼 ?找方法啊。经过翻山越岭我们终于找到了。
哎呀呀,这是什么吊东西。说白了。就是它的父view是同一个的时候执行。否则直接抛异常咯。
接下来就是:
经过我几般周折。终于了解了一丢丢。这是加工从父view中获取的触摸事件。这个方法将分发callback回调事件。父view的触摸事件实现中应该调用该方法。说白了,这是处理ontouch事件的~~~
好了。稍微介绍下ViewDragHelper的原理和几个重点:
1.ViewDragHelper用于监听整个拖拽事件的开始到结束,过程分三步:休息,开始拖动,结束拖动。
2.ViewDragHelper的拖拽是通过Scoller实现的。
3.ViewDragHelper是有保存历史记录的。例如我从(0,0)滚动到(100,0),那么下次滚动肯定是从后者继续滚动,而不是前者了。
4。 有历史记录,当然也有清空记录的功能,ViewDragHelper提供了cancel()方法,类似onTouch的ACTION_UP事件。当拖曳结束,可能系统还认为过程还在,因此就需要提供的cancel()或abort()方法去终止这个过程,同时也自动调用clearMotionHistory()方法,置空历史记录。确保下次触摸拖曳事件是”新的开始”。
5.ViewDragHelper的拖拽事件是根据父view的最顶层的子view才会响应事件。所以该类提供了public View findTopChildUnder(int x, int y)方法捕获父view中最顶层的子view对象。
好了。应该没什么要说了的把?如果还有什么疑问,可以提出来,一起讨论。
先来个测试demo的效果图。
下面直接上代码:
/** * Created by Angel on 2016/11/26. */ public class ViewDragHelperLayout extends LinearLayout { private ViewDragHelper helper; public ViewDragHelperLayout(Context context) { super(context); inital(); } public ViewDragHelperLayout(Context context, AttributeSet attrs) { super(context, attrs); inital(); } private void inital() { helper = ViewDragHelper.create(this, 1.0f, new ViewDragCallback()); } private class ViewDragCallback extends ViewDragHelper.Callback { public boolean tryCaptureView(View view, int id) { return true; } public void onViewDragStateChanged(int state) { super.onViewDragStateChanged(state); } public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); } public void onViewCaptured(View capturedChild, int activePointerId) { super.onViewCaptured(capturedChild, activePointerId); } public int clampViewPositionHorizontal(View child, int left, int dx) { //让我们的视图不越界 int paddingleft = getPaddingLeft(); int view_width = child.getWidth(); int view_left = getWidth() - view_width - paddingleft; int new_left = Math.min(Math.max(paddingleft, left), view_left); return new_left; } public int clampViewPositionVertical(View child, int top, int dy) { return 0; } } public boolean onInterceptTouchEvent(MotionEvent event) { return helper.shouldInterceptTouchEvent(event); } public boolean onTouchEvent(MotionEvent event) { helper.processTouchEvent(event); return true; } }
好了,回归整体,从源码角度开始分析,接下来要放大招了~~~
ViewDragHelper并不强大,强大的是他有一个回调函数
我们点开ViewDragHelper的源码,找到他的回调:
public abstract static class Callback { public 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) { } public int getOrderedChildIndex(int index) { return index; } public int getViewHorizontalDragRange(View child) { return 0; } public int getViewVerticalDragRange(View child) { return 0; } public abstract boolean tryCaptureView(View var1, int var2); public int clampViewPositionHorizontal(View child, int left, int dx) { return 0; } public int clampViewPositionVertical(View child, int top, int dy) { return 0; } }
接下来,我们分析一下他们分别是什么时候才会调用的。
onViewDragStateChanged
当ViewDragHelper状态变更时回调该方法
onViewPositionChanged
当捕获view由于拖曳或者设定而发生位置变更时回调
onViewCaptured
当子view被由于拖曳而被捕获时回调的方法.
onViewReleased
手指释放的时候回调
onEdgeTouched
当触摸到边界时回调。
onEdgeLock
true的时候会锁住当前的边界,false则unLock。
onEdgeDragStarted
在边界拖动时回调
getOrderedChildIndex
改变同一个坐标(x,y)去寻找captureView位置的方法。
getViewHorizontalDragRange
getViewVerticalDragRange
这两个的返回值大于0时才可捕获
tryCaptureView
是否捕捉该view的滚动,id代表捕捉某一个view的滚动
clampViewPositionHorizontal
左右滑动时调用
clampViewPositionVertical
上下滑动时调用
到这边,应该所有的方法都介绍完了。好了,现在我们来聊聊,ViewDragHelper的方法。
创建一个ViewDragHelper对象
helper.create(forParent, cb); helper.create(forParent, sensitivity, cb);
至于有小伙伴对sensitivity这个属性有疑问,那么我们点开源码来了解下他是干嘛的。
public static ViewDragHelper create(ViewGroup forParent, float sensitivity, ViewDragHelper.Callback cb) { ViewDragHelper helper = create(forParent, cb); helper.mTouchSlop = (int)((float)helper.mTouchSlop * (1.0F / sensitivity)); return helper; }
我们传入的值越大,他的值越小。但mTochSlop是怎么计算的呢,我们继续看源码:
private ViewDragHelper(Context context, ViewGroup forParent, ViewDragHelper.Callback cb) { if(forParent == null) { throw new IllegalArgumentException("Parent view may not be null"); } else if(cb == null) { throw new IllegalArgumentException("Callback may not be null"); } else { this.mParentView = forParent; this.mCallback = cb; ViewConfiguration vc = ViewConfiguration.get(context); float density = context.getResources().getDisplayMetrics().density; this.mEdgeSize = (int)(20.0F * density + 0.5F); this.mTouchSlop = vc.getScaledTouchSlop(); this.mMaxVelocity = (float)vc.getScaledMaximumFlingVelocity(); this.mMinVelocity = (float)vc.getScaledMinimumFlingVelocity(); this.mScroller = ScrollerCompat.create(context, sInterpolator); } }
我们定位到了这个:vc.getScaledTouchSlop();这个属性是用来干嘛的呢。我查了下。解释如下:
getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件。如果小于这个距离就不触发移动控件。
现在不要我多说了把。就是你一次最少滑动的距离要大于这个距离,否则,视图是不会移动了。
好了,现在看我们之前的demo还用到了什么。
helper.shouldInterceptTouchEvent(event);
继续看源码:
public boolean shouldInterceptTouchEvent(MotionEvent ev) { ... ... ... return mDragState == 1; }
等于1是什么鬼 ?找方法啊。经过翻山越岭我们终于找到了。
public void captureChildView(View childView, int activePointerId) { if(childView.getParent() != this.mParentView) { throw new IllegalArgumentException("captureChildView: parameter must be a descendant of the ViewDragHelper\'s tracked parent view (" + this.mParentView + ")"); } else { this.mCapturedView = childView; this.mActivePointerId = activePointerId; this.mCallback.onViewCaptured(childView, activePointerId); this.setDragState(1); } }
哎呀呀,这是什么吊东西。说白了。就是它的父view是同一个的时候执行。否则直接抛异常咯。
接下来就是:
helper.processTouchEvent(event);
经过我几般周折。终于了解了一丢丢。这是加工从父view中获取的触摸事件。这个方法将分发callback回调事件。父view的触摸事件实现中应该调用该方法。说白了,这是处理ontouch事件的~~~
好了。稍微介绍下ViewDragHelper的原理和几个重点:
1.ViewDragHelper用于监听整个拖拽事件的开始到结束,过程分三步:休息,开始拖动,结束拖动。
2.ViewDragHelper的拖拽是通过Scoller实现的。
3.ViewDragHelper是有保存历史记录的。例如我从(0,0)滚动到(100,0),那么下次滚动肯定是从后者继续滚动,而不是前者了。
4。 有历史记录,当然也有清空记录的功能,ViewDragHelper提供了cancel()方法,类似onTouch的ACTION_UP事件。当拖曳结束,可能系统还认为过程还在,因此就需要提供的cancel()或abort()方法去终止这个过程,同时也自动调用clearMotionHistory()方法,置空历史记录。确保下次触摸拖曳事件是”新的开始”。
5.ViewDragHelper的拖拽事件是根据父view的最顶层的子view才会响应事件。所以该类提供了public View findTopChildUnder(int x, int y)方法捕获父view中最顶层的子view对象。
好了。应该没什么要说了的把?如果还有什么疑问,可以提出来,一起讨论。
相关文章推荐
- ViewDragHelper,入门级源码分析
- ViewDragHelper源码分析
- ViewDragHelper的源码分析及概述学习
- Android源码角度分析View的scrollBy()和scrollTo()的参数正负问题
- Android ViewDragHelper源码笔记
- ViewDragHelper实现分析
- 从源码的角度分析ViewGruop的事件分发
- 从源码的角度分析ViewGruop的事件分发
- 从源码角度分析ViewStub 疑问与原理
- Android ViewDragHelper源码解析
- Android View 绘制流程 与invalidate 和postInvalidate 分析--从源码角度
- ImageView (一) ——从源码的角度分析ScaleType (缩放模式)
- 从源码角度带你分析 Android View 事件分发 dispatchTouchEvent,onTouch,onTouchEvent,onClick逻辑顺序过程(一)
- 从源码的角度分析ViewGruop的事件分发
- Android源码角度分析View的scrollBy()和scrollTo()的参数正负问题
- View的两种更新方法-从源码角度分析invalidate()和postInvalidate()的区别
- 从源码角度分析view的draw过程
- Android应用ViewDragHelper详解及部分源码浅析
- ViewDragHelper 部分原理分析
- [置顶] 带你从源码角度分析ViewGroup中事件分发流程