Android Touch事件总结 二 (双指实现RecyclerView的快速滚动)
来源:互联网 发布:免费pk10分析软件 编辑:程序博客网 时间:2024/05/17 04:14
说明:本博客为原创,转载请注明出处 CSDN-ANDROID笔记栈
由于作者水平有限,错误在所难免,请见谅,可以留言,本人会及时改正
索引
- MotionEvent
- Demo
在 Android Touch事件总结 一 中介绍了Android Touch事件的分发,拦截,消费。
本篇是对总结一的补充和实战。
MotionEvent
在分发、拦截、消费方法中传入的参数都是MotionEvent对象,所以有必要对MotionEvent类进行分析,大家可以参考这篇博文:Android MotionEvent详解
我重点强调下MotionEvnet的几个方法在多指触摸事件中的作用:
getActionIndex:在ACTION_POINTER_DOWN和ACTION_POINTER_UP事件中返回索引
getPointerId:通过索引获取id
findPointerIndex:通过id获取索引
pointerId在整个触摸事件[DOWN->UP]中是不变的,但是index可能会变。
Demo
GitHub地址: GitHub
环境: Windows7+JAVA8
IDE: AndroidStdio2.2.2
compileSdkVersion:24
测试设备:Nexus5(6.0.1)
运行结果截图:
黑色和黑色线是手指的移动轨迹,30%是整个移动轨迹相对于View整个高度的百分比(向下滑动>0,向上滑动<0)
只有双指滑动在支持快递滚动(RecyclerView中的Touch事件被拦截),单指没有效果(RecyclerView正常滚动)
下面是核心代码:
@Overridepublic boolean dispatchTouchEvent(MotionEvent ev){ switch (ev.getActionMasked()) { case MotionEvent.ACTION_DOWN: { resetFinger(); // 重置手指状态 final int pointerId = ev.getPointerId(ev.getActionIndex()); // 获取当前手指(单手指)的id final int index = ev.findPointerIndex(pointerId); mFirstFinger = new Finger(pointerId); // 初始化第一根手指 TouchPoint touchPoint = new TouchPoint(ev.getX(index), ev.getY(index)); // 保存当前的坐标x&y值 // 这边需要说明的是调用ArrayList.add(MotionEvent) 之后整个List中的值都会被最新添加的对象给覆盖!未查明原因,有知道原因的请告知,谢谢。 mFirstFinger.add(touchPoint); // 添加到ArrayList中 mFirstFinger.setTargetPoint(touchPoint); break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_OUTSIDE: { mFingerTouchMode = false; // 标志位,用于什么时候拦截Touch事件 resetFinger(); // 重置手指 break; } case MotionEvent.ACTION_MOVE: { if (mFirstFinger != null) { final int index = ev.findPointerIndex(mFirstFinger.id); TouchPoint touchPoint = new TouchPoint(ev.getX(index), ev.getY(index)); mFirstFinger.add(touchPoint); // 添加手指移动轨迹 if (mSecondFinger == null) { mFirstFinger.setTargetPoint(touchPoint); } } if (mSecondFinger != null) // 如果是多指状态,添加第二根手指的移动轨迹 { final int index = ev.findPointerIndex(mSecondFinger.id); TouchPoint touchPoint = new TouchPoint(ev.getX(index), ev.getY(index)); mSecondFinger.add(touchPoint); } if (mFirstFinger != null && mSecondFinger != null) // 如果是多指状态,则计算移动距离百分比 { if (Math.abs(mFirstFinger.touchTime - mSecondFinger.touchTime) <= FINGER_TOUCH_DURATION) // 两根手指的触摸时间<500毫秒 { int fd = mFirstFinger.getDistanceFromTargetPoint(); // 计算第一根手指的移动距离 int sd = mSecondFinger.getDistanceFromTargetPoint(); // 计算第二根手指的移动距离 if (fd * sd > 0) // 两根手指同向 { mFingerTouchMode = true; int dDelta = (fd + sd) / 2; mPercent = Math.min((int) (dDelta * 100f * mScale / getHeight()), 100); // 计算百分比 if (mCallback != null) { mCallback.onFingerScrolling(mPercent);// 触发回调事件 } } } } break; } case MotionEvent.ACTION_POINTER_DOWN: // 多指状态 { if (mSecondFinger == null) // 初始化第二根手指 { final int pointerId = ev.getPointerId(ev.getActionIndex()); final int index = ev.findPointerIndex(pointerId); mSecondFinger = new Finger(pointerId); TouchPoint touchPoint = new TouchPoint(ev.getX(index), ev.getY(index)); mSecondFinger.add(touchPoint); mSecondFinger.setTargetPoint(touchPoint); if (mCallback != null) { mCallback.onFingerStart(); } } break; } case MotionEvent.ACTION_POINTER_UP: { mFingerTouchMode = ev.getPointerCount() > 2; // 判断当前是不是多指状态 final int pointerUpId = ev.getPointerId(ev.getActionIndex()); // 获取当前是哪根手指触发了UP事件 if (mFirstFinger != null && pointerUpId == mFirstFinger.id) // 如果是第一根手指,交换手指顺序 { mFirstFinger = mSecondFinger; mFirstFinger.resetTargetPoint(); mSecondFinger = null; } else if (mSecondFinger != null && pointerUpId == mSecondFinger.id) { if (mFirstFinger != null) mFirstFinger.resetTargetPoint(); mSecondFinger = null; } if (mCallback != null) { mCallback.onFingerEnd(); } mPercent = 0; break; } } if (!mFingerTouchMode) // 如果是当前是多指滑动状态,拦截Touch事件,这里是没有调用super方法(不会分发该事件) // onInterceptionTouchEvent 只能拦截当前是DOWN事件或者是FirstTouchTarget对象不为空的时候!什么时候不为空,还没有搞明白! { super.dispatchTouchEvent(ev); } invalidate(); // 把移动轨迹在onDraw中画出来 return true; }
xml布局
<com.neulion.android.dl.touchdemo.widget.DLMultipleFingerScrollLayout android:id="@+id/dl_multiple_finger_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#ffffff"> <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" /> </com.neulion.android.dl.touchdemo.widget.DLMultipleFingerScrollLayout>
具体的实现可以在GitHub上下载源码。
0 0
- Android Touch事件总结 二 (双指实现RecyclerView的快速滚动)
- RecyclerView的touch事件
- Android RecyclerView 详解(二) 点击事件绑定、瀑布流和Grid的实现
- RecyclerView进阶(二)点击事件的实现
- Android Touch事件传递的一些总结
- Android中Touch事件的总结
- Android中Touch事件的总结
- RecyclerView的Item点击事件实现总结
- RecyclerView的滚动事件分析
- RecyclerView的滚动事件研究
- RecyclerView的滚动事件分析
- RecyclerView的滚动事件分析
- android RecyclerView响应点击事件(二)
- 移动端的touch事件(二)
- Android Touch事件传递总结
- Android Touch事件总结 一
- 横向ListView (二)—— 添加快速滚动功能及item相关事件实现
- android的touch事件
- 阿里云云监控安装指南
- 下载微信文章中腾讯视频的方法
- 二分查找 插值查找
- 员工没热情?这8个简单方法比加薪都管用
- Mybatis基础知识(2)
- Android Touch事件总结 二 (双指实现RecyclerView的快速滚动)
- 常用类库object类
- npm使用指南
- 我的第一篇博客
- python dict的一些简单用法
- 制作一个简单的照片查看器(支持缩放手势)
- Android studio约束布局 ConstraintLayout
- Spring 初探(一)(Spring起步实例)
- leetcode--Isomorphic Strings