Behavior子类SwipeDismissBehavior简单分析
2016-04-15 11:45
344 查看
在前一篇文章CoordinatorLayout里Behavior简单分析的基础上继续简单分析SwipeDismissBehavior的简单实现。
SwipeDismissBehavior作用,如果View设置SwipeDismissBehavior那么这个View是可以设置左右滑动的,同时往左边滑动的时候会去改变View的透明度,往右边滑动不会改变View的透明度。(注意View并不会消失的,只是有的时候设置了透明度你看不见而已)。
下面从SwipeDismissBehavior源码的角度看看SwipeDismissBehavior是怎么工作的。SwipeDismissBehavior继承自CoordinatorLayout.Behavior(我们知道CoordinatorLayout.Behavior的使用我们分了三种情况)。这里SwipeDismissBehavior只是关注CoordinatorLayout.Behavior 的 onInterceptTouchEvent和onTouchEvent方法。也就是CoordinatorLayout里Behavior简单分析里面说的Behavior的第一种情况。
SwipeDismissBehavior里面都是使用ViewDragHelper帮助类来处理我们SwipeDismissBehavior对应View的拖拽手势操作。按照ViewDragHelper的使用规则我们就直接看ViewDragHelper的Callback类。
直接看里面主要的几个函数了
1. tryCaptureView函数,保存了我们触摸到的View距离父控件左边的距离。return true。接收手势了。
2. onViewDragStateChanged 直接给listener了。
3. onViewReleased 手势释放的时候调用。找到View最终要到达的位置(指定位置还是回到原位置)。看下shouldDismiss函数具体干了什么事情,第41行如果水平方向有速度(fling的时候不为0,scroll的时候为0)判断是哪个方向的要不要直接到制定的位置去。如果水平方向速度为0(scroll) 则是去判断滑动的距离是否超过了一半(默认是一半可以自己设置)。
4. clampViewPositionHorizontal 水平方向移动。
5. clampViewPositionVertical 垂直方向不移动。
6. onViewPositionChanged 设置在移动的过程中设置透明度。
SwipeDismissBehavior的onInterceptTouchEvent函数。CoordinatorLayout里面是怎么调用到这个函数里面来的CoordinatorLayout里Behavior简单分析有简单的介绍。
SwipeDismissBehavior的onInterceptTouchEvent函数会在CoordinatorLayout的onInterceptTouchEvent函数中调用到。先把intercept的权利交给了SwipeDismissBehavior的onInterceptTouchEvent。SwipeDismissBehavior会对触摸点判断是否在SwipeDismissBehavior对应的View位置之内。判断是否走到mViewDragHelper.shouldInterceptTouchEvent(event);
同样SwipeDismissBehavior的onTouchEvent
调用了mViewDragHelper.processTouchEvent(event);这样所有的处理都到了mViewDragHelper的Callback函数里面去了,在里面做一些相应的处理如前面对Callback的描述。
几个相关函数的解释
总结SwipeDismissBehavior具体干了什么事情。
当触摸到SwipeDismissBehavior对应的View的时候,View会更随手指滑动。如果是往左边滑动的时候View的透明度会改变,如果是右边滑动透明度则是不会变的。
注:这里有发现一个问题,如果CoordinatorLayout里面有A View和B View。如果我们只给A View设置了SwipeDismissBehavior。当我们触摸B View的时候B View也会有滑动消失的效果。因为在ViewDragHelper的Callback的tryCaptureView所有的View都是返回的ture。
最后给个简单的DEMO下载地址
SwipeDismissBehavior作用,如果View设置SwipeDismissBehavior那么这个View是可以设置左右滑动的,同时往左边滑动的时候会去改变View的透明度,往右边滑动不会改变View的透明度。(注意View并不会消失的,只是有的时候设置了透明度你看不见而已)。
下面从SwipeDismissBehavior源码的角度看看SwipeDismissBehavior是怎么工作的。SwipeDismissBehavior继承自CoordinatorLayout.Behavior(我们知道CoordinatorLayout.Behavior的使用我们分了三种情况)。这里SwipeDismissBehavior只是关注CoordinatorLayout.Behavior 的 onInterceptTouchEvent和onTouchEvent方法。也就是CoordinatorLayout里Behavior简单分析里面说的Behavior的第一种情况。
SwipeDismissBehavior里面都是使用ViewDragHelper帮助类来处理我们SwipeDismissBehavior对应View的拖拽手势操作。按照ViewDragHelper的使用规则我们就直接看ViewDragHelper的Callback类。
private final ViewDragHelper.Callback mDragCallback = new ViewDragHelper.Callback() { private int mOriginalCapturedViewLeft; @Override public boolean tryCaptureView(View child, int pointerId) { mOriginalCapturedViewLeft = child.getLeft(); return true; } @Override public void onViewDragStateChanged(int state) { if (mListener != null) { mListener.onDragStateChanged(state); } } @Override public void onViewReleased(View child, float xvel, float yvel) { final int childWidth = child.getWidth(); int targetLeft; boolean dismiss = false; if (shouldDismiss(child, xvel)) { targetLeft = child.getLeft() < mOriginalCapturedViewLeft ? mOriginalCapturedViewLeft - childWidth : mOriginalCapturedViewLeft + childWidth; dismiss = true; } else { // Else, reset back to the original left targetLeft = mOriginalCapturedViewLeft; } if (mViewDragHelper.settleCapturedViewAt(targetLeft, child.getTop())) { ViewCompat.postOnAnimation(child, new SettleRunnable(child, dismiss)); } else if (dismiss && mListener != null) { mListener.onDismiss(child); } } private boolean shouldDismiss(View child, float xvel) { if (xvel != 0f) { final boolean isRtl = ViewCompat.getLayoutDirection(child) == ViewCompat.LAYOUT_DIRECTION_RTL; if (mSwipeDirection == SWIPE_DIRECTION_ANY) { // We don't care about the direction so return true return true; } else if (mSwipeDirection == SWIPE_DIRECTION_START_TO_END) { // We only allow start-to-end swiping, so the fling needs to be in the // correct direction return isRtl ? xvel < 0f : xvel > 0f; } else if (mSwipeDirection == SWIPE_DIRECTION_END_TO_START) { // We only allow end-to-start swiping, so the fling needs to be in the // correct direction return isRtl ? xvel > 0f : xvel < 0f; } } else { final int distance = child.getLeft() - mOriginalCapturedViewLeft; final int thresholdDistance = Math.round(child.getWidth() * mDragDismissThreshold); return Math.abs(distance) >= thresholdDistance; } return false; } @Override public int getViewHorizontalDragRange(View child) { return child.getWidth(); } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { final boolean isRtl = ViewCompat.getLayoutDirection(child) == ViewCompat.LAYOUT_DIRECTION_RTL; int min, max; if (mSwipeDirection == SWIPE_DIRECTION_START_TO_END) { if (isRtl) { min = mOriginalCapturedViewLeft - child.getWidth(); max = mOriginalCapturedViewLeft; } else { min = mOriginalCapturedViewLeft; max = mOriginalCapturedViewLeft + child.getWidth(); } } else if (mSwipeDirection == SWIPE_DIRECTION_END_TO_START) { if (isRtl) { min = mOriginalCapturedViewLeft; max = mOriginalCapturedViewLeft + child.getWidth(); } else { min = mOriginalCapturedViewLeft - child.getWidth(); max = mOriginalCapturedViewLeft; } } else { min = mOriginalCapturedViewLeft - child.getWidth(); max = mOriginalCapturedViewLeft + child.getWidth(); } return clamp(min, left, max); } @Override public int clampViewPositionVertical(View child, int top, int dy) { return child.getTop(); } @Override public void onViewPositionChanged(View child, int left, int top, int dx, int dy) { final float startAlphaDistance = mOriginalCapturedViewLeft + child.getWidth() * mAlphaStartSwipeDistance; final float endAlphaDistance = mOriginalCapturedViewLeft + child.getWidth() * mAlphaEndSwipeDistance; if (left <= startAlphaDistance) { ViewCompat.setAlpha(child, 1f); } else if (left >= endAlphaDistance) { ViewCompat.setAlpha(child, 0f); } else { // We're between the start and end distances final float distance = fraction(startAlphaDistance, endAlphaDistance, left); ViewCompat.setAlpha(child, clamp(0f, 1f - distance, 1f)); } } };
直接看里面主要的几个函数了
1. tryCaptureView函数,保存了我们触摸到的View距离父控件左边的距离。return true。接收手势了。
2. onViewDragStateChanged 直接给listener了。
3. onViewReleased 手势释放的时候调用。找到View最终要到达的位置(指定位置还是回到原位置)。看下shouldDismiss函数具体干了什么事情,第41行如果水平方向有速度(fling的时候不为0,scroll的时候为0)判断是哪个方向的要不要直接到制定的位置去。如果水平方向速度为0(scroll) 则是去判断滑动的距离是否超过了一半(默认是一半可以自己设置)。
4. clampViewPositionHorizontal 水平方向移动。
5. clampViewPositionVertical 垂直方向不移动。
6. onViewPositionChanged 设置在移动的过程中设置透明度。
SwipeDismissBehavior的onInterceptTouchEvent函数。CoordinatorLayout里面是怎么调用到这个函数里面来的CoordinatorLayout里Behavior简单分析有简单的介绍。
@Override public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { switch (MotionEventCompat.getActionMasked(event)) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: // Reset the ignore flag if (mIgnoreEvents) { mIgnoreEvents = false; return false; } break; default: mIgnoreEvents = !parent.isPointInChildBounds(child, (int) event.getX(), (int) event.getY()); break; } if (mIgnoreEvents) { return false; } ensureViewDragHelper(parent); return mViewDragHelper.shouldInterceptTouchEvent(event); }
SwipeDismissBehavior的onInterceptTouchEvent函数会在CoordinatorLayout的onInterceptTouchEvent函数中调用到。先把intercept的权利交给了SwipeDismissBehavior的onInterceptTouchEvent。SwipeDismissBehavior会对触摸点判断是否在SwipeDismissBehavior对应的View位置之内。判断是否走到mViewDragHelper.shouldInterceptTouchEvent(event);
同样SwipeDismissBehavior的onTouchEvent
@Override public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) { if (mViewDragHelper != null) { mViewDragHelper.processTouchEvent(event); return true; } return false; }
调用了mViewDragHelper.processTouchEvent(event);这样所有的处理都到了mViewDragHelper的Callback函数里面去了,在里面做一些相应的处理如前面对Callback的描述。
几个相关函数的解释
/** * 设置View滑动的方向 SWIPE_DIRECTION_START_TO_END(右),SWIPE_DIRECTION_END_TO_START(左),SWIPE_DIRECTION_ANY(两个方向都可以) 三个当中的一个 */ public void setSwipeDirection(@SwipeDirection int direction) /** * 设置当手指放开的时候滑动的距离达到改设置值*View的宽度的时候 会自动偏移View的宽度的位置 */ public void setDragDismissDistance(float distance) /** * 透明度开始变化的位置(当滑动的距离达到改设置值*View的宽度的时候透明度开始变化) */ public void setStartAlphaSwipeDistance(float fraction) /** * 透明度结束变化的位置(当滑动的距离达到改设置值*View的宽度的时候透明度结束变化) */ public void setEndAlphaSwipeDistance(float fraction) /** * 用于设置ViewDragHelper的touchSlop */ public void setSensitivity(float sensitivity)
总结SwipeDismissBehavior具体干了什么事情。
当触摸到SwipeDismissBehavior对应的View的时候,View会更随手指滑动。如果是往左边滑动的时候View的透明度会改变,如果是右边滑动透明度则是不会变的。
注:这里有发现一个问题,如果CoordinatorLayout里面有A View和B View。如果我们只给A View设置了SwipeDismissBehavior。当我们触摸B View的时候B View也会有滑动消失的效果。因为在ViewDragHelper的Callback的tryCaptureView所有的View都是返回的ture。
最后给个简单的DEMO下载地址
相关文章推荐
- x64共享库中的位置无关代码(PIC)
- TCP 连接断连问题剖析
- 解决listview更新数据时,屏幕闪烁的问题
- UTF-8,GB2312,UNICODE,字符集Windows平台互转类,简单高效
- 设计模式 - 享元模式
- 网络编程相关知识
- 图像特征之 Haar-like特征(一)概述及特征值数量计算
- 进程间通信之信号量
- 数据建模那点事儿
- ElasticSearch2.3.1环境搭建哪些不为人知的坑
- 小绿人小红人和小黄人
- 项目学习经验
- Google 地图 API V3 之事件
- 文章标题
- 手动配置Android Studio中的Gradle
- android透明状态栏
- 苹果审核失败相关申诉
- malloc、ralloc、calloc的用法,作用,区别,及实现原理
- SGU 135 Drawing Lines(dp)
- Java 二分查找