前言

转载请声明,转自【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的更多相关文章

  1. 【朝花夕拾】Android自定义View篇之(八)多点触控(上)MotionEvent简介

    前言 在前面的文章中,介绍了不少触摸相关的知识,但都是基于单点触控的,即一次只用一根手指.但是在实际使用App中,常常是多根手指同时操作,这就需要用到多点触控相关的知识了.多点触控是在Android2 ...

  2. 【朝花夕拾】Android自定义View篇之(六)Android事件分发机制(中)从源码分析事件分发逻辑及经常遇到的一些“诡异”现象

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/11039252.html]谢谢! 在上一篇文章[[朝花夕拾]Android自定义View篇之(五 ...

  3. 【朝花夕拾】Android自定义View篇之(四)自定义View的三种实现方式及自定义属性使用介绍

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10979161.html],谢谢! 尽管Android系统提供了不少控件,但是有很多酷炫效果仍然 ...

  4. 【朝花夕拾】Android自定义View篇之(一)View绘制流程

    前言 转载请申明转自[https://www.cnblogs.com/andy-songwei/p/10955062.html]谢谢! 自定义View.多线程.网络,被认为是Android开发者必须牢 ...

  5. 【朝花夕拾】Android自定义View篇之(九)多点触控(下)实践出真知

    前言 在上一篇文章中,已经总结了MotionEvent以及多点触控相关的基础理论知识和常用的函数.本篇将通过实现单指拖动图片,多指拖动图片的实际案例来进行练习并实现一些效果,来理解前面的理论知识.要理 ...

  6. 【朝花夕拾】Android自定义View篇之(五)Android事件分发机制(上)Touch三个重要方法的处理逻辑

    前言 转载请注明,转自[https://www.cnblogs.com/andy-songwei/p/10998855.html]谢谢! 在自定义View中,经常需要处理Android事件分发的问题, ...

  7. 【朝花夕拾】Android自定义View篇之(十一)View的滑动,弹性滑动与自定义PagerView

    前言 由于手机屏幕尺寸有限,但是又经常需要在屏幕中显示大量的内容,这就使得必须有部分内容显示,部分内容隐藏.这就需要用一个Android中很重要的概念——滑动.滑动,顾名思义就是view从一个地方移动 ...

  8. 【朝花夕拾】Android自定义View篇之(二)Canvas常用功能

    前言 转在请申明,转自[https://www.cnblogs.com/andy-songwei/p/10960012.html],谢谢! 上一篇讲View的绘制流程中讲到过,最后一步是draw流程, ...

  9. 【朝花夕拾】Android自定义View篇之(七)Android事件分发机制(下)滑动冲突解决方案总结

    前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/11072989.html],谢谢! 前面两篇文章,花了很大篇幅讲解了Android的事件分发机制 ...

随机推荐

  1. 启动组织重整 Marvell追求创新文化

    最近接任Marvell技术长的Neil Kim正是该公司亟需的人才——他在今年四月加入后,预计将为Marvell带来正面.积极的改革契机,有机会让该公司彻底改头换面... 迈威尔科技(Marvell) ...

  2. wpf VisualBrush 的使用,可创建重复图像

    VisualBrush 类(msdn) <Grid.Background> <VisualBrush TileMode="Tile" Viewport=" ...

  3. UWP入门(二) -- 基础笔记

    原文:UWP入门(二) -- 基础笔记 不错的UWP入门视频,1092417123,欢迎交流 UWP-04 - What i XMAL? XAML - XML Syntax(语法) ,create i ...

  4. Android进程间通信-AIDL实现原理

    Android进程间通信基于Proxy(代理)与Stub(桩或存根)的设计模式(如图1-1所示).其中,Proxy将特殊性接口转换成通用性接口,Stub将通用性接口转换成特殊性接口,二者之间的数据转换 ...

  5. Docker Explanation and Apache Image

    https://blog.sajjan.com.np/2017/02/05/docker-getting-started-containers-ubuntu/ https://blog.sajjan. ...

  6. 青云QingCloud宣布完成C轮融资,金额1亿美元

    本轮融资由两家人民币基金领投,蓝驰创投跟投. 企业级基础云服务商青云QingCloud正式宣布完成金额为1亿美元的C轮融资,本轮融资由两家人民币基金领投,蓝驰创投跟投. 青云QingCloud公司成立 ...

  7. window下搭建qt开发环境编译、引用ace

    工作中经常用到ace.tao等,在windwo下的c++开发工具基本上就是vs20xx这些工具,还有些就是类似编辑工具例如:source insight等,前者比较大,打开.编译运行比较慢,二期针对a ...

  8. ngnix 安装

    1安装PCRE库 ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/ 下载最新的 PCRE 源码包,使用下面命令下载编译和安装 PCRE 包: ...

  9. java集合的方法及使用详解

    一.java集合的分类及相互之间的关系 Collection接口:向下提供了List和Set两个子接口 |------List接口:存储有序的,存储元素可以重复 |------ArrayList(主要 ...

  10. 使用Hibernate连接Oracle 无法识别生成的SQL问题

    问题: 在JAVA工程中,数据库使用的是OracleXE(Oracle10g Express Edition). 使用hibernate.reveng.xml创建了实体类及其DAO类,如: tt.my ...