【朝花夕拾】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 a
movement 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
这里我们顺便看看该方法的源码:
//======android.view.ViewConfiguration.java======
private final int mTouchSlop;
/**
* @return Distance in pixels a touch can wander before we think the user is scrolling
*/
public int getScaledTouchSlop() {
return mTouchSlop;
}
......
private ViewConfiguration(Context context) {
......
mTouchSlop = res.getDimensionPixelSize( com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
......
}
二、VelocityTracker
该类用于速度追踪,追踪手指在滑动过程中的速度,包括水平方向速度和竖直方向速度。在前面的文章中介绍滑动冲突的解决方法时,就提到过通过比较水平方向速度和竖直方向速度来判断控件的滑动方向。这里我们简单介绍一下获取速度的方法。
1、初始化
进行初始化,获取VelocityTracker实例,通过如下方法实现:
VelocityTracker mVelocityTracker = VelocityTracker.obtain();
其源码如下:
/**
* Retrieve a new VelocityTracker object to watch the velocity of a
* motion. Be sure to call {@link #recycle} when done. You should
* generally only maintain an active object while tracking a movement,
* so that the VelocityTracker can be re-used elsewhere.
*
* @return Returns a new VelocityTracker.
*/
static public VelocityTracker obtain() {
VelocityTracker instance = sPool.acquire();
return (instance != null) ? instance : new VelocityTracker(null);
}
可见,VelocityTracker原本有一个“池”,“池”中的实例用完后才会新实例一个。注释中包含了很多信息,什么时候调用等,最好参照这个注释说明来做。
2、添加用户事件
由于要追踪事件的速度,所以需要向VelocityTracker中添加事件。使用如下方式进行添加:
mVelocityTracker.addMovement(event);
源码如下:
/**
* Add a user's movement to the tracker. You should call this for the
* initial {@link MotionEvent#ACTION_DOWN}, the following
* {@link MotionEvent#ACTION_MOVE} events that you receive, and the
* final {@link MotionEvent#ACTION_UP}. You can, however, call this
* for whichever events you desire.
*
* @param event The MotionEvent you received and would like to track.
*/
public void addMovement(MotionEvent event) {
if (event == null) {
throw new IllegalArgumentException("event must not be null");
}
nativeAddMovement(mPtr, event);
}
......
private static native void nativeAddMovement(long ptr, MotionEvent event);
这方法可以在任何你希望的事件中进行调用。
3、计算速度
在获取速度前必须先计算速度,使用方法如下:
mVelocityTracker.computeCurrentVelocity(int units);
我们在计算速度的时候,都需要指定时间单位,比如km/h,m/s等,表示在单位时间内的运动路程。这里的units单位为ms,得到的速度表示单位时间内移动的像素数目。比如这里参数为1000时,那么后续获得的速度就是,每1000ms移动的像素数。
该方法的源码如下:
/**
* Equivalent to invoking {@link #computeCurrentVelocity(int, float)} with a maximum
* velocity of Float.MAX_VALUE.
*
* @see #computeCurrentVelocity(int, float)
*/
public void computeCurrentVelocity(int units) {
nativeComputeCurrentVelocity(mPtr, units, Float.MAX_VALUE);
}
......
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轴正方向为负。前面我们也说过了,这里的速度是指,给定的时间间隔内,手指所滑过的像素数。
源码如下:
/**
* Retrieve the last computed X velocity. You must first call
* {@link #computeCurrentVelocity(int)} before calling this function.
*
* @return The previously computed X velocity.
*/
public float getXVelocity() {
return nativeGetXVelocity(mPtr, ACTIVE_POINTER_ID);
}
/**
* Retrieve the last computed Y velocity. You must first call
* {@link #computeCurrentVelocity(int)} before calling this function.
*
* @return The previously computed Y velocity.
*/
public float getYVelocity() {
return nativeGetYVelocity(mPtr, ACTIVE_POINTER_ID);
}
......
private static native float nativeGetXVelocity(long ptr, int id);
private static native float nativeGetYVelocity(long ptr, int id);
注释中也明确说明了,获取速度前,必须先计算速度。
5、重置并回收内存
当不再需要使用上述VelocityTracker实例时,需要重置并回收内存,使用方法如下:
mVelocityTracker.recycle();
对应源码如下:
/**
* Return a VelocityTracker object back to be re-used by others. You must
* not touch the object after calling this function.
*/
public void recycle() {
if (mStrategy == null) {
clear();
sPool.release(this);
}
}
......
/**
* Reset the velocity tracker back to its initial state.
*/
public void clear() {
nativeClear(mPtr);
}
......
private static native void nativeClear(long ptr);
6、使用示例
这里举一个实例来演示上述方法的使用。
public class VelocityView extends View {
private static final String TAG = "songzheweiwang";
private VelocityTracker mVelocityTracker;
public VelocityView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mVelocityTracker = VelocityTracker.obtain();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mVelocityTracker.addMovement(event);
switch (event.getActionMasked()) {
case MotionEvent.ACTION_UP:
mVelocityTracker.computeCurrentVelocity(1000);
float xVelocity = mVelocityTracker.getXVelocity();
float yVelocity = mVelocityTracker.getYVelocity();
Log.i(TAG, "xVelocity=" + xVelocity + ";yVelocity=" + yVelocity);
break;
}
return true;
}
@Override
protected void onDetachedFromWindow() {
Log.i(TAG, "onDetachedFromWindow");
mVelocityTracker.recycle();
super.onDetachedFromWindow();
}
}
这里只是简单演示这些方法的使用,仅做参考之用,读者可以根据实际情况来使用它们。
在界面上滑动,使用完后退出该界面,打印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
【朝花夕拾】Android自定义View篇之(十)TouchSlop及VelocityTracker的更多相关文章
- 【朝花夕拾】Android自定义View篇之(八)多点触控(上)MotionEvent简介
前言 在前面的文章中,介绍了不少触摸相关的知识,但都是基于单点触控的,即一次只用一根手指.但是在实际使用App中,常常是多根手指同时操作,这就需要用到多点触控相关的知识了.多点触控是在Android2 ...
- 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...
- 【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10979161.html],谢谢! 尽管Android系统提供了不少控件,但是有很多酷炫效果仍然 ...
- 【朝花夕拾】Android自定义View篇之(一)View绘制流程
前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...
- 【朝花夕拾】Android自定义View篇之(九)多点触控(下)实践出真知
前言 在上一篇文章中,已经总结了MotionEvent以及多点触控相关的基础理论知识和常用的函数.本篇将通过实现单指拖动图片,多指拖动图片的实际案例来进行练习并实现一些效果,来理解前面的理论知识.要理 ...
- 【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑
前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/10998855.html]谢谢! 在自定义View中,经常需要处理Android事件分发的问题, ...
- 【朝花夕拾】Android自定义View篇之(十一)View的滑动,弹性滑动与自定义PagerView
前言 由于手机屏幕尺寸有限,但是又经常需要在屏幕中显示大量的内容,这就使得必须有部分内容显示,部分内容隐藏.这就需要用一个Android中很重要的概念——滑动.滑动,顾名思义就是view从一个地方移动 ...
- 【朝花夕拾】Android自定义View篇之(二)Canvas常用功能
前言 转在请申明,转自[https://www.cnblogs.com/andy-songwei/p/10960012.html],谢谢! 上一篇讲View的绘制流程中讲到过,最后一步是draw流程, ...
- 【朝花夕拾】Android自定义View篇之(七)Android事件分发机制(下)滑动冲突解决方案总结
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/11072989.html],谢谢! 前面两篇文章,花了很大篇幅讲解了Android的事件分发机制 ...
随机推荐
- java.text.MessageFormat 专题
java.text.MessageFormat类MessageFormat提供一种语言无关的方式来组装消息,它允许你在运行时刻用指定的参数来替换掉消息字符串中的一部分.你可以为MessageForma ...
- python3. 报“ImportError: No module named ‘MySQLdb'”
需要安装PyMysql pip install PyMysql 然后在程序中引入 import pymysql pymysql.install_as_MySQLdb() app.config['SQL ...
- TCPClient组件和TCPServer组件的主要方法和属性
IdTCPClient属性1 : IOHandler 如果有相应的输入/输出操作,那么IOHandler相对应的组件或接口将提供一个虚拟/抽象的输入/输出接口给相应的网络连接2 : Intercept ...
- 利用WIX制作安装包(1)
原文 利用WIX制作安装包(1) #installation 下载最新版本的WIX toolset 并安装DOWNLOAD Wix toolset V3.5之后的版本已经可以集成到visual stu ...
- WPF WindowChrome 自定义窗口
1.wpf自定义窗口: WindowChrome类描述:https://msdn.microsoft.com/zh-cn/library/system.windows.shell.windowchro ...
- 使用Arcgis Pro 发布矢量切片
ArcGIS Pro 中的任何地图或底图都可以创建矢量切片,但是有一些局限性和特殊注意事项.为创建矢量切片制作地图的重点是构建一个有效的地图,以快速绘制生成的切片. 软件环境 操作系统:Windows ...
- java统计文本中单词出现的个数
package com.java_Test; import java.io.File; import java.util.HashMap; import java.util.Iterator; imp ...
- 基于 ZooKeeper 搭建 Spark 高可用集群
一.集群规划 二.前置条件 三.Spark集群搭建 3.1 下载解压 3.2 配置环境变量 3.3 集群配置 3.4 安装包分发 四.启 ...
- Hive —— 安装部署
一.安装Hive 1.1 下载并解压 下载所需版本的Hive,这里我下载版本为cdh5.15.2.下载地址:http://archive.cloudera.com/cdh5/cdh/5/ # 下载后进 ...
- ZooKeeper —— 单机环境和集群环境搭建
一.单机环境搭建 1.1 下载 下载对应版本Zookeeper,这里我下载的版本3.4.14.官方下载地址:https://archive.apache.org/dist/zookeeper/ # w ...