滑动实现原理

滑动的产生

View的滑动,本质上是移动View,即改变View所处的位置,这点和动画效果类似,都是通过不断改变View的坐标来实现的。

因此,要产生滑动效果,需要监听用户的触摸事件,根据事件的坐标信息不断改变View的坐标,使View跟随用户的触摸进行移动。

滑动是相对的移动,要实现滑动,就必须了解Android系统中的坐标体系和触摸事件(MotionEvent),接下来对坐标体系和触摸事件进行说明。

系统坐标系

Android系统的坐标系如下图所示:

系统坐标系

系统提供了getLocationOnScreen()方法获取View在系统坐标系的位置,即该View左上角在系统坐标系的位置。

触摸事件中触摸点的系统坐标使用getRawX()和getRawY()方法获取。

视图坐标系

除了系统坐标系,Android中还有视图坐标系,它用来描述子View在父View中的位置,系统坐标系如下图所示:

视图坐标系

触摸事件中触摸点的视图坐标使用getX()和getY()方法获取。

触摸事件与坐标系

触摸事件MotionEvent中封装了常用的事件常量,这些常量定义了不同的类型的触摸事件,可以使用getAction()方法获取。

下面用一幅图来描述一些获取坐标值和相对距离的常用API:

坐标系常用API

根据上图,可以得出View的宽高和坐标的关系:

1
2
width = right - left
height = bottom - top

从Android3.0开始,View增加了额外参数:x、y、translationX和translationY,其中x和y是View左上角的坐标,而translationX和translationY是View左上角相对于父View的偏移量。View的各个位置参数的关系如下:

1
2
x = left + translationX
y = top + translationY

需要注意的是,View在移动过程中,left和top表示的是最初左上角的位置信息,其值不会发生改变,具体发生变化的是x、y、translationX和translationY这几个参数。

滑动相关的对象

MotionEvent只能获取最基本的触摸事件,如果要获取更丰富的触摸信息,去实现用户体验更好的滑动效果,那么需要使用下面介绍的相关对象。

TouchSlop

TouchSlop表示系统能够识别出的最小滑动距离,如果在屏幕上进行滑动操作时,滑动的距离小于这个常量,系统会忽略这个滑动操作。这个常量与具体设备有关,不同的设备上值可能不同,获取方式如下:

1
ViewConfiguration.get(getContext()).getScaledTouchSlop();

在具体处理滑动时,可以使用这个常量做一些过滤,比如,当滑动的距离小于这个常量时,忽略这个滑动操作,这样可以有更好的用户体验。

VelocityTracker

VelocityTracker用来追踪滑动的速度,包括水平和垂直方向的速度。使用方式如下:

  • 在View的onTouchEvent()方法中追踪当前事件的速度:
1
2
VelocityTracker tracker = VelocityTracker.obtain();
tracker.addMovement(event);
  • 速度追踪完毕后,获取当前事件的速度:
1
2
3
tracker.computeCurrentVelocity(1000);
int xVelocity = (int) tracker.getXVelocity();
int yVelocity = (int) tracker.getYVelocity();
  • 不需要使用时,回收资源:
1
2
tracker.clear();
tracker.recycle();

GestureDetector

GestureDetector用于手势检测,可以用来辅助检测用户的单击、滑动、长按、双击等手势。一般使用分为两步:

  • 创建GestureDetector对象并实现OnGestureListener接口
  • 在目标View的onTouchEvent()方法中调用GestureDetector.onTouchEvent(event)方法

当然,在实际开发中,可以不使用GestureDetector,不过建议:如果只监听滑动相关的事件,可以直接在View的onTouchEvent()方法中实现,如果要监听双击等事件,最好使用GestureDetector。

坚持原创技术分享,您的支持将鼓励我继续创作!