【朝花夕拾】Android自定义View篇之(十)移动阈值TouchSlop及滑动追踪VelocityTracker...
前言
转载请声明,转自【https://www.cnblogs.com/andy-songwei/p/11193433.html】谢谢!
在Android事件中,有几个比较基本的概念和知识点需要掌握。比如,表示最小移动阈值的TouchSlop,追踪事件速度的VelocityTracker,用于检测手势的GestureDetector,实现View弹性滑动的Scroller,用户帮助处理View和事件的辅助工具类ViewDragView等。这些都是使用事件、理解事件中需要掌握的知识点。本篇将简单介绍Slop和VelocityTracker的基本知识。
一、TouchSlop
TouchSlop是一个系统常量,用于表示系统能够识别的被认为是滑动的最小距离,也就是说当在屏幕上滑动的距离小于这个值时,系统不认为这是滑动操作。这个值和设备有关,手机生产商可以自行设置该值。通过该值,可以过滤掉一些滑动距离太小的操作等,从而提高用户体验。该值保存在文件frameworks/base/core/res/res/values/config.xml中,如下所示:
<!-- Base "touch slop" value used by ViewConfiguration as amovement threshold where scrolling should begin. --> <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
默认情况下,该值一般都是8dp。
Log.i("songzheweiwang", "TouchSlop=" + ViewConfiguration.get(this).getScaledTouchSlop());
打印log为(测试机的density=3.0):
07-15 17:02:22.382 6789-6789/com.example.demos I/songzheweiwang: TouchSlop=24
这里我们顺便看看该方法的源码:
1 //======android.view.ViewConfiguration.java====== 2 private final int mTouchSlop; 3 /** 4 * @return Distance in pixels a touch can wander before we think the user is scrolling 5 */ 6 public int getScaledTouchSlop() { 7 return mTouchSlop; 8 } 9 ...... 10 private ViewConfiguration(Context context) { 11 ...... 12 mTouchSlop = res.getDimensionPixelSize( com.android.internal.R.dimen.config_viewConfigurationTouchSlop); 13 ...... 14 }
二、VelocityTracker
该类用于速度追踪,追踪手指在滑动过程中的速度,包括水平方向速度和竖直方向速度。在前面的文章中介绍滑动冲突的解决方法时,就提到过通过比较水平方向速度和竖直方向速度来判断控件的滑动方向。这里我们简单介绍一下获取速度的方法。
1、初始化
进行初始化,获取VelocityTracker实例,通过如下方法实现:
VelocityTracker mVelocityTracker = VelocityTracker.obtain();
其源码如下:
1 /** 2 * Retrieve a new VelocityTracker object to watch the velocity of a 3 * motion. Be sure to call {@link #recycle} when done. You should 4 * generally only maintain an active object while tracking a movement, 5 * so that the VelocityTracker can be re-used elsewhere. 6 * 7 * @return Returns a new VelocityTracker. 8 */ 9 static public VelocityTracker obtain() { 10 VelocityTracker instance = sPool.acquire(); 11 return (instance != null) ? instance : new VelocityTracker(null); 12 }
可见,VelocityTracker原本有一个“池”,“池”中的实例用完后才会新实例一个。注释中包含了很多信息,什么时候调用等,最好参照这个注释说明来做。
2、添加用户事件
由于要追踪事件的速度,所以需要向VelocityTracker中添加事件。使用如下方式进行添加:
mVelocityTracker.addMovement(event);
源码如下:
1 /** 2 * Add a user's movement to the tracker. You should call this for the 3 * initial {@link MotionEvent#ACTION_DOWN}, the following 4 * {@link MotionEvent#ACTION_MOVE} events that you receive, and the 5 * final {@link MotionEvent#ACTION_UP}. You can, however, call this 6 * for whichever events you desire. 7 * 8 * @param event The MotionEvent you received and would like to track. 9 */ 10 public void addMovement(MotionEvent event) { 11 if (event == null) { 12 throw new IllegalArgumentException("event must not be null"); 13 } 14 nativeAddMovement(mPtr, event); 15 } 16 ...... 17 private static native void nativeAddMovement(long ptr, MotionEvent event);
这方法可以在任何你希望的事件中进行调用。
3、计算速度
在获取速度前必须先计算速度,使用方法如下:
mVelocityTracker.computeCurrentVelocity(int units);
我们在计算速度的时候,都需要指定时间单位,比如km/h,m/s等,表示在单位时间内的运动路程。这里的units单位为ms,得到的速度表示单位时间内移动的像素数目。比如这里参数为1000时,那么后续获得的速度就是,每1000ms移动的像素数。
该方法的源码如下:
1 /** 2 * Equivalent to invoking {@link #computeCurrentVelocity(int, float)} with a maximum 3 * velocity of Float.MAX_VALUE. 4 * 5 * @see #computeCurrentVelocity(int, float) 6 */ 7 public void computeCurrentVelocity(int units) { 8 nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE); 9 } 10 ...... 11 private static native void nativeComputeCurrentVelocity(long ptr, int units, float maxVelocity);
4、获取速度
前面我们说了,在获取速度前,一定要先计算速度。获取速度通过如下两个方法来完成:
float xVelocity = mVelocityTracker.getXVelocity();float yVelocity = mVelocityTracker.getYVelocity();
这两行代码分别用于获取水平方向和竖直方向的速度。我们知道,速度是有方向的,以不同的方向为标准,速度就有正负。在这里获取的速度,是以X轴正相反为正,即顺着X轴正方向时速度为正,逆着X轴正方向时速度为负。同样,对于竖直方向,顺着Y轴正方向为正,逆着Y轴正方向为负。前面我们也说过了,这里的速度是指,给定的时间间隔内,手指所滑过的像素数。
源码如下:
1 /** 2 * Retrieve the last computed X velocity. You must first call 3 * {@link #computeCurrentVelocity(int)} before calling this function. 4 * 5 * @return The previously computed X velocity. 6 */ 7 public float getXVelocity() { 8 return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID); 9 } 10 /** 11 * Retrieve the last computed Y velocity. You must first call 12 * {@link #computeCurrentVelocity(int)} before calling this function. 13 * 14 * @return The previously computed Y velocity. 15 */ 16 public float getYVelocity() { 17 return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID); 18 } 19 ...... 20 private static native float nativeGetXVelocity(long ptr, int id); 21 private static native float nativeGetYVelocity(long ptr, int id);
注释中也明确说明了,获取速度前,必须先计算速度。
5、重置并回收内存
当不再需要使用上述VelocityTracker实例时,需要重置并回收内存,使用方法如下:
mVelocityTracker.recycle();
对应源码如下:
1 /** 2 * Return a VelocityTracker object back to be re-used by others. You must 3 * not touch the object after calling this function. 4 */ 5 public void recycle() { 6 if (mStrategy == null) { 7 clear(); 8 sPool.release(this); 9 } 10 } 11 ...... 12 /** 13 * Reset the velocity tracker back to its initial state. 14 */ 15 public void clear() { 16 nativeClear(mPtr); 17 } 18 ...... 19 private static native void nativeClear(long ptr);
6、使用示例
这里举一个实例来演示上述方法的使用。
1 public class VelocityView extends View { 2 private static final String TAG = "songzheweiwang"; 3 private VelocityTracker mVelocityTracker; 4 5 public VelocityView(Context context, @Nullable AttributeSet attrs) { 6 super(context, attrs); 7 mVelocityTracker = VelocityTracker.obtain(); 8 } 9 10 @Override 11 public boolean onTouchEvent(MotionEvent event) { 12 mVelocityTracker.addMovement(event); 13 switch (event.getActionMasked()) { 14 case MotionEvent.ACTION_UP: 15 mVelocityTracker.computeCurrentVelocity(1000); 16 float xVelocity = mVelocityTracker.getXVelocity(); 17 float yVelocity = mVelocityTracker.getYVelocity(); 18 Log.i(TAG, "xVelocity=" + xVelocity + ";yVelocity=" + yVelocity); 19 break; 20 } 21 return true; 22 } 23 24 @Override 25 protected void onDetachedFromWindow() { 26 Log.i(TAG, "onDetachedFromWindow"); 27 mVelocityTracker.recycle(); 28 super.onDetachedFromWindow(); 29 } 30 }
这里只是简单演示这些方法的使用,仅做参考之用,读者可以根据实际情况来使用它们。
在界面上滑动,使用完后退出该界面,打印log为:
07-16 10:15:18.951 10338-10338/com.example.demos I/songzheweiwang: xVelocity=643.2775;yVelocity=543.7565 07-16 10:15:26.406 10338-10338/com.example.demos I/songzheweiwang: onDetachedFromWindow
转载于:https://www.cnblogs.com/andy-songwei/p/11193433.html
【朝花夕拾】Android自定义View篇之(十)移动阈值TouchSlop及滑动追踪VelocityTracker...相关推荐
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发机制...
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
- android自定义起止时间的时间刻度尺,Android 自定义View篇(六)实现时钟表盘效果...
前言 Android 自定义 View 是高级进阶不可或缺的内容,日常工作中,经常会遇到产品.UI 设计出花里胡哨的界面.当系统自带的控件不能满足开发需求时,就只能自己动手撸一个效果. 本文就带自定义 ...
- android 自定义裁剪 陌陌,Android之View篇6————仿陌陌卡片左右滑动选择布局
Android之View篇6----仿陌陌卡片左右滑动选择控件 一.目录 Android之View篇6----仿陌陌卡片左右滑动选择控件 一.目录 二.效果图 三.业务需求梳理 四.思路分析 1. 新 ...
- 【朝花夕拾】Android自定义View篇之(一)View绘制流程
前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...
- 【朝花夕拾】Android自定义View篇之(十一)View的滑动,弹性滑动与自定义PagerView...
前言 转载请声明,转载自[https://www.cnblogs.com/andy-songwei/p/11213718.html],谢谢! 由于手机屏幕尺寸有限,但是又经常需要在屏幕中显示大量的内容 ...
- android canvas_Android 自定义View篇(七)实现环形进度条效果
前言 Android 自定义 View 是高级进阶不可或缺的内容,日常工作中,经常会遇到产品.UI 设计出花里胡哨的界面.当系统自带的控件不能满足开发需求时,就只能自己动手撸一个效果. 本文就带自定义 ...
- Android自定义View绘制流程
Android视图层次结构简介 在介绍View绘制流程之前,咱们先简单介绍一下Android视图层次结构以及DecorView,因为View的绘制流程的入口和DecorView有着密切的联系. 我们平 ...
- 精通Android自定义View(十四)绘制水平向右加载的进度条
1引言 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制三部曲综合 ...
- 精通Android自定义View(十二)绘制圆形进度条
1 绘图基础简析 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制 ...
最新文章
- pandas使用nsmallest函数返回特定数据列中前N个最小值(搜寻最小的n个元素)、pandas使用nsmallest函数返回特定数据列中前N个最小值所对应的数据行
- WIN配置git 配置后失败 can't be established
- ListView加checkBox可以实现全选等功能
- maven错误The JAVA_HOME environment variable is not defined correctly
- python适合零基础的人吗_学Python需要什么基础知识?零基础可以学Python吗?
- 如果你恨一个程序员,忽悠他去做iOS开发
- linux桌面环境应用
- jq动态渲染后获取不到元素高度_浏览器的渲染机制
- (6)售货机verilog与Systemverilog编码
- 387. First Unique Character in a String - String
- Excel转PDF方法
- 手机照片局部放大镜_往事洗照片
- 现金流量表的编制 (by shany shang)
- 有可控冷热水隔板的储水式电热水器
- 书论29 颜真卿《怀素上人草书歌序》
- 属性动画、帧动画、补间动画的介绍使用及对比
- 2020年中国地理信息产业现状分析,发展前景广阔「图」
- oracle_sod,sod: PDF.NET 的追求:代码的精简,开发、维护的简单与极致的运行效率!...
- Mybatis源码分析: MapperMethod功能讲解
- 微信小程序周日历制作
热门文章
- 使用JavaBean创建您的网上日历本(2)
- log4cxx linux 使用,log4cxx在Linux下的编译使用
- 前端_http协议_html语言headbody基本介绍和用法
- 研究背调:云安全--CASB、CSPM、CWPP
- 年轻人要明白,职场里不只有晋升
- 大数据时代:数据收集比数据挖掘更有意义
- 基于 Netty 重构 RPC 框架
- Jquery插件实现“点击获取验证码后60秒内禁止重新获取(防刷新)”
- 什么是QT(轻松的帮你做带界面的软件)
- c#Form未能加载文件或程序集的解决方法