前言

转载请声明,转自【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. 如何将svg转换为xaml

    原文:如何将svg转换为xaml 1 下载Inkscape 2 用Inkscape打开svg,另存为xaml 注意:复杂的svg图转换完会出现类似下面的xaml,wpf/silverlight是无法解 ...

  2. MEF、MAF和Unity的区别

    在刚学习MEF时,经常会问一个问题,那就是MEF和MAF这样的插件框架.和Unity这样的IoC框架到底有什么区别.MEF与MAF(Managed Addin Framework)最大不同在于:前者关 ...

  3. Markdown 入门

    一. Markdown语法的简要规则 标题 标题是非常重要的一个标记,一段文字标记为标题,只需要在文字前加 #.具体可以支持到1到6个# 1 2 3 4 # 一级标题 ## 二级标题 ### 三级标题 ...

  4. 微信小程序把玩(三十六)Storage API

    原文:微信小程序把玩(三十六)Storage API 其实这个存储在新建Demo的时候就已经用到了就是存储就是那个logs日志,数据存储主要分为同步和异步 异步存储方法: 存数据 wx.setStor ...

  5. AndroidStudio问题汇总

    1.Error:Execution failed for task ':app:preDebugAndroidTestBuild'.> Conflict with dependency 'com ...

  6. IntelliJ IDEA的jsp中内置对象方法无法被解析的解决办法

    主要原因是因为缺乏依赖 可以通过添加依赖的方式 导入servlet-api.jar,jsp-api.jar,tomcat-api.jar 这三个jar即可 这三个jar在tomcat的lib目录下有 ...

  7. abp(net core)+easyui+efcore仓储系统——定义仓储并实现 (四)

    abp(net core)+easyui+efcore仓储系统目录 abp(net core)+easyui+efcore仓储系统——ABP总体介绍(一) abp(net core)+easyui+e ...

  8. 使用LinkedList模拟一个堆栈或者队列数据结构。

    堆栈:先进后出 First in last out filo 队列:先进先出 First in last out filo使用LinkedList的方法,addFirst addLast getFir ...

  9. screen命令使用简单说明

    首先用screen [-S]命令建立一个session,然后就可以在这个session中建立多个window了.使用screen [-S]可以建立多个session,而每个session又可以建立多个 ...

  10. 关于web系统整体优化提速总结

    关于web系统整体优化提速总结 一.背景 随着公司业务的拓展,随之而来就是各种系统横向和纵向的增加,PV.UV也都随之增加,原有的系统架构和模式慢慢遇上了瓶颈,需要逐步的对系统从整体上进行改造升级,通 ...