滑动的产生
View的滑动,本质上是移动View,即改变View所处的位置,这点和动画效果类似,都是通过不断改变View的坐标来实现的。
因此,要产生滑动效果,需要监听用户的触摸事件,根据事件的坐标信息不断改变View的坐标,使View跟随用户的触摸进行移动。
滑动是相对的移动,要实现滑动,就必须了解Android系统中的坐标体系和触摸事件(MotionEvent),接下来对坐标体系和触摸事件进行说明。
系统坐标系
Android系统的坐标系如下图所示:
系统提供了getLocationOnScreen()方法获取View在系统坐标系的位置,即该View左上角在系统坐标系的位置。
触摸事件中触摸点的系统坐标使用getRawX()和getRawY()方法获取。
视图坐标系
除了系统坐标系,Android中还有视图坐标系,它用来描述子View在父View中的位置,系统坐标系如下图所示:
触摸事件中触摸点的视图坐标使用getX()和getY()方法获取。
触摸事件与坐标系
触摸事件MotionEvent中封装了常用的事件常量,这些常量定义了不同的类型的触摸事件,可以使用getAction()方法获取。
下面用一幅图来描述一些获取坐标值和相对距离的常用API:
根据上图,可以得出View的宽高和坐标的关系:
1 | width = right - left |
从Android3.0开始,View增加了额外参数:x、y、translationX和translationY,其中x和y是View左上角的坐标,而translationX和translationY是View左上角相对于父View的偏移量。View的各个位置参数的关系如下:
1 | x = left + translationX |
需要注意的是,View在移动过程中,left和top表示的是最初左上角的位置信息,其值不会发生改变,具体发生变化的是x、y、translationX和translationY这几个参数。
滑动相关的对象
MotionEvent只能获取最基本的触摸事件,如果要获取更丰富的触摸信息,去实现用户体验更好的滑动效果,那么需要使用下面介绍的相关对象。
TouchSlop
TouchSlop表示系统能够识别出的最小滑动距离,如果在屏幕上进行滑动操作时,滑动的距离小于这个常量,系统会忽略这个滑动操作。这个常量与具体设备有关,不同的设备上值可能不同,获取方式如下:
1 | ViewConfiguration.get(getContext()).getScaledTouchSlop(); |
在具体处理滑动时,可以使用这个常量做一些过滤,比如,当滑动的距离小于这个常量时,忽略这个滑动操作,这样可以有更好的用户体验。
VelocityTracker
VelocityTracker用来追踪滑动的速度,包括水平和垂直方向的速度。使用方式如下:
- 在View的onTouchEvent()方法中追踪当前事件的速度:
1 | VelocityTracker tracker = VelocityTracker.obtain(); |
- 速度追踪完毕后,获取当前事件的速度:
1 | tracker.computeCurrentVelocity(1000); |
- 不需要使用时,回收资源:
1 | tracker.clear(); |
GestureDetector
GestureDetector用于手势检测,可以用来辅助检测用户的单击、滑动、长按、双击等手势。一般使用分为两步:
- 创建GestureDetector对象并实现OnGestureListener接口
- 在目标View的onTouchEvent()方法中调用GestureDetector.onTouchEvent(event)方法
当然,在实际开发中,可以不使用GestureDetector,不过建议:如果只监听滑动相关的事件,可以直接在View的onTouchEvent()方法中实现,如果要监听双击等事件,最好使用GestureDetector。