Android View 事件基础
View 基础知识
本节主要介绍:View的位置参数、MotionEvent和TouchSlop、VelocityTracker,GestureDetector和Scroller对象
什么是View
View是Android中所有控件的基类,是界面层的一种抽象,代表了一个控件。除了View还有ViewGroup,ViewGroup继承于View,内部是可以有子View的,这个子View同样还可以是ViewGroup,因此View本身可以是单个控件也可以是由多个控件组成的一组控件,通过这种关系形成了View树结构。根据这个概念,我们知道Button显然是个View,LinearLayout不但是一个View而且还是一个ViewGroup。
View的位置参数
View的位置主要由它的四个属性来决定:top、left、right,bottom,其中top是左上角纵坐标,left是左上角横坐标,right是右下角横坐标,bottom是右下角纵坐标。需要注意的是,这些坐标都是相对于View的父容器的相对坐标,在Android和大部分显示系统中都是按照x轴和y轴的正方向分别为右和下来定义坐标系的。
从图中可以得到宽高和坐标的关系:
width = right - left
height = bottom - top
从Android3.0开始,View增加了额外的几个参数,x,y,translationX,translationY,其中x,y是View左上角的坐标,而translationX,translationY是左上角相对父容器的偏移量,这几个参数也是相对于父容器的坐标,并且translationX,translationY的默认值是0,换算关系如下:
x = left + translationX
y = top + translationY
需要注意的是,View在平移的过程中,top和left表示在原始左上角的位置信息,其值并不会发生什么,此时发生改变的是x,y,translationX,translationY,这四个参数。
MotionEvent和TouchSlop
MotionEvent
MotionEvent的典型事件有如下几种:
- ACTION_DOWN——手指刚接触屏幕
- ACTION_MOVE——手指在屏幕上移动
- ACTION_UP——手机从屏幕上松开的一瞬间
一次手指触摸屏幕行为会触发一系列点击事件:
- DOWN->UP——点击屏幕后离开松开
- DOWN->MOVE->…->MOVE->UP——点击屏幕滑动一会再松开
通过MotionEvent对象可以得到点击事件发生的x和y坐标:getX/getY和getRawX/getRawY,区别是getX/getY返回的是相对于当前View左上角的x和y坐标,而geiRawX/getRawY返回的是相对于手机屏幕左上角的x和y坐标
TouchSlop
TouchSlop是系统所能识别出的被认为是滑动的最小距离,它是一个常量,在不同的设备下这个值可能不同,当处理滑动时利用它来做一些过滤,两次滑动之间的距离小于这个值,就可以不认为在做滑动操作
TouchSlop获取方式:
ViewConfigurtion.get(getContext()).getScaledTouchSlop
TouchSlop在源码中的位置:
fraweworks/base/core/res/values/config.xml中的config_viewConfigurationTouchSlop
VelocityTracker、GestureDetector和Scroller
VelocityTracker
速度追踪,用于追踪手指在屏幕上滑动的速度,包括水平和竖直方向上的速度
使用方式:
首先在View的onTouchEvent方法里追踪当前点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
接着,当我们先知道当前的滑动速度时,这个时候可以采用如下的方式得到当前的速度
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
有两点需要注意:
- 获取速度的之前必须先计算速度,即getXVelocity和getYVelocity这两个方法前面一定要调用computeCurrentVelocity方法。
- 这里的速度是指一段时间内手指滑动的屏幕像素数,比如将时间设置为1000ms时,在1s内,手指在水平方向手指滑动100像素,那么水平速度就是100,当手指从右向左滑动的时候,速度即为负
速度的计算公式如下表示:
速度 = (终点位置 - 起点位置)/ 时间段
最后,当不需要使用它的时候,需要调用clear方法来重置并回收内存:
velocityTracker.clear();
velocityTracker.recycle();
GestureDetector
手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为
使用方式:
首先创建对象
GestureDetector mGestureDetector = new GestureDetector(this);
//解决长按屏幕后无法拖动的现象
mGestureDetector.setIsLongPressEnabled(false);
接着,接管目标View的onTouchEvent方法
boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
然后就能有选择性的实现OnGestureListener和OnDoubleTapListener中的方法了,这两个接口中的方法介绍如下图:
方法名 | 描述 | 所属接口 |
---|---|---|
onDown | 手指轻触屏幕一瞬间,由1个ACTION_DOWN触发 | OnGestureListener |
onShowPress | 手指轻触屏幕,尚未松开或拖动,由1个ACTION_DOWN触发 *注意和onDown()区别,它强调的是没有松开或者拖动的状态 | OnGestureListener |
onSingleTapUp | 单击,伴随着1个ACTION_UP触发 | OnGestureListener |
onScroll | 拖动,由1个ACTION_DOWN,多个ACTION_MOVE触发 | OnGestureListener |
onLongPass | 长按 | OnGestureListener |
onFling | 快速滑动,由1个ACTION_DOWN,多个ACTION_MOVE触发和1个ACTION_UP触发 | OnGestureListener |
onDoubleTap | 双击,由2次连续的单击组成,不可能和onSingleTapConfirmed共存 | OnDoubleTapListener |
onSingleTapConfirmed | 严格的单击行为 *注意和onSingleTapUp的区别,如果触发了onSingleTapConfirmed,那后面不可能再紧跟着另一个单击行为,即这是可能是单击,不可能是双击中的一次单击 | OnDoubleTapListener |
onDoubleTapEvent | 表示发生了双击行为,在双击期间,ACTION_DOWN、ACTION_MOVE和ACTION_UP都会触发此回调 | OnDoubleTapListener |
Scroller
用于实现View的弹性滑动,当使用View的scrollTo/scrollBy方法来进行滑动时,会瞬间完成这个动作,没有过渡效果的滑动用户体验不好,这个时候就可以用Scroller来实现过度效果的滑动
Scroller需要和view的computScrioll方法配合才能完成弹性滑动,使用方式如下:
Scroller mScroller = new Scroller(mContext);
// 缓慢滚动到指定位置
private void smoothScrollTo(int destX,int destY){
int scrollX = getScrollX();
int delta = destX - scrollX;
//1000ms内滑向destX,效果就是慢慢滑动
mScroller.startScroll(scrollX,0,delta,0,1000);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()){
scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
postInvalidate();
}
}