View的事件体系

来源:互联网 发布:大米评测的淘宝店 编辑:程序博客网 时间:2024/05/20 18:55

Android屏幕坐标系如下图:
http://www.stormzhang.com/android/2013/07/14/android-ontouchlistener-and-ongesturelistener/
Android的坐标系
这里写图片描述
(1)MotionEvent中 e1是手指第一次按上屏幕的起点,e2是抬起手指离开屏幕的终点,根据上图Android屏幕坐标系可知:

手指向右滑动,终点(e2)在起点(e1)的右侧,有e2.getX() - e1.getX() 大于0
手指向左滑动,终点(e2)在起点(e1)的左侧,有e2.getX() - e1.getX() 小于0
手指向下滑动,终点(e2)在起点(e1)的下侧,有e2.getY() - e1.getY() 大于0
手指向上滑动,终点(e2)在起点(e1)的上侧,有e2.getY() - e1.getY() 小于0

(2)onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)

distanceX,是前后两次call的X距离,不是e2与e1的水平距离 distanceX,是前后两次call的Y距离,不是e2与e1的垂直距离 具体数值的方向,请详见上图(中)

(3)onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)

velocityX,是X轴的每秒速度 velocityY,是Y轴的每秒速度 具体数值的方向,请详见上图(右) 仔细观察可以发现:velocityX、velocityY的方向与distanceX、distanceY方向正好相反

1.View基础知识

(1)View的位置参数
这里写图片描述
view坐标
View的位置由它的四个顶点来决定:
top是左上角纵坐标,
left是左上角横坐标,
right是右下角横坐标,
bottom是右下角纵坐标
这些坐标都是相对View的父容器来说的,因此是相对坐标。
在Android中,x轴和y轴的正方向分别为右和下。

width = right - left;
height = bottom - top;

如何得到这个四个参数:在View源码中对应为mLeft,mRight,mTop,mBottom
这四个成员变量,获取方式:
Left = getLeft;
Right = getRight;
Top = getTop();
Bottom = getBottom();

从Android 3.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。

例子:
这里写图片描述
例子
10-09 23:15:01.950: D/TAG(1283): Left=40
10-09 23:15:01.950: D/TAG(1283): Right=189
10-09 23:15:01.950: D/TAG(1283): Top=40
10-09 23:15:01.950: D/TAG(1283): Bottom=78
10-09 23:15:01.950: D/TAG(1283): x=40.0
10-09 23:15:01.950: D/TAG(1283): y=40.0
10-09 23:15:01.950: D/TAG(1283): translationX=0.0
10-09 23:15:01.950: D/TAG(1283): translationY=0.0

一开始的时候,x = left,y = top,如果此时移动TextView,
那么,left,top不变,translationX,translationY发生变化,
从而x和y发生变化。
x,y始终表示当前view的左上角的坐标,是会变化的。

(2)MotionEvent和TouchSlop
MotionEvent:
在手指接触屏幕后所产生的一系列事件中,典型的有下面几种:
ACTION_DOWN:手指刚接触屏幕
ACTION_MOVE:手指在屏幕上面移动
ACTION_UP:手指从屏幕上松开的一瞬间
正常情况下,一次手指触摸的行为会触发一系列的点击事件,
点击屏幕后离开松开,事件序列为DOWN–>UP;
点击屏幕滑动一会再松开,事件序列为DOWN->MOVE->…->MOVE->UP;
通过MotionEvent对象我们可以得的点击事件发生的x和y坐标,系统提供了两组方法,getX,getY,返回当前点击的x,y坐标(以当前view为参考的),getRawX,getRawY,返回的是点击的位置相对于手机屏幕左上角的x和y坐标。
如上面的TextView的一次点击情况如下:
10-13 23:43:59.566: D/TAG(1255): x=2.9440842
10-13 23:43:59.566: D/TAG(1255): y=17.840744
10-13 23:43:59.566: D/TAG(1255): rawX=42.944084
10-13 23:43:59.566: D/TAG(1255): rawY=203.84074

TouchSlop:
系统所能识别的被认为是滑动的最小距离。
ViewConfiguration. get(getContext()).getScaledTouchSlop();

(3)VelocityTracker,GestureDetector,Scroller
VelocityTracker:
速度追踪,用于追踪手指在滑动过程中的速度,包括水平方向和竖直方向的速度。
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
当想知道当前的速度的时候,
velocityTracker.computeCurrentVelocity(1000);
int xVelocity=(int)velocityTracke.getXVelocity();
int yVelocity=(int)velocityTracke.getYVelocity();
注意,获取速度前必须先计算,就是computeCurrentVelocity方法,速度指手指在一段时间所滑过的像素。

从右往左滑动为负,从下往上滑动为负。也就是逆着坐标系为负。

不需要使用的时候,
velocityTracke.clear();
velocityTracke.recycle();

GestureDetector:
手势检测,用户辅助检测用户的单击,滑动,长按,双击等行为。
创建对象:
GestureDetector mGestureDetector = new GestureDetector(this);
// 解决长按屏幕后无法拖动的现象
mGestureDetector.setIsLongpressEnabled(false);
接着,接管目标view的onTouchEvent方法,在onTouchEvent里面
boolean consume= mGestureDetector.onTouchEvent(event);
return consume;

然后就可以选择实现onGestureListener和onDoubleTabListener里面
的方法了。
这里写图片描述
GestureDetector里面方法
GestureDetector里面方法

里面的方法很多,但是并不是所有的方法都会被时常用到,常用的有:
onSingleTapUp(单击),onFling(快速滑动),onScroll(拖动),
onLongPress(长按),onDoubleTap(双击)。

实际的开发中,可以不使用GestureDetector,完全可以在onTouchEvent
里面实现所需要的监听。

建议:
如果只是监听滑动相关的,建议自己在onTouchEvent里面实现,如果需要监听双击这种行为的话,就使用GestureDetector。

Scroller:
弹性滑动对象,当使用View的scrollTo/scrollBy方法进行滑动的时候,其过程是
瞬时完成的,这个没有过度效果的滑动,用户体验不好。
Scroller滑动不是瞬时完成的,而是在一定的时间断内完成的,Scroller本身无法
让view弹性滑动,需要和view的comuteScroll方法配合使用。
典型代码如下:

  @Override  public void computeScroll() {         if ( mScroller != null) {               if ( mScroller.computeScrollOffset()) {                    scrollTo( mScroller.getCurrX(), mScroller.getCurrY());                    postInvalidate(); // So we draw agai                    ViewCompat.postInvalidateOnAnimation(this);                                       }        }  }  private void smoothScrollTo(int destX, int destY) {         int scrollX = getScrollX();         int delta = destX - scrollX;         // 1000ms内滑向destX,效果就是慢慢滑动         mScroller.startScroll( scrollX, 0, delta, 0, 1000);        invalidate();  }

2.View的滑动

三种方法:
view本身提供的scrollTo/scrollBy方法;
通过动画给view添加平移效果来实现;
通过改变view的LayoutParams使得view重新布局。
(1)使用scrollTo/scrollBy
这两个方法的实现:

/** * Set the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the x position to scroll to * @param y the y position to scroll to */public void scrollTo( int x, int y) {    if (mScrollX != x || mScrollY != y) {        int oldX = mScrollX;        int oldY = mScrollY;        mScrollX = x;        mScrollY = y;        invalidateParentCaches();        onScrollChanged( mScrollX, mScrollY, oldX, oldY);        if (!awakenScrollBars()) {            postInvalidateOnAnimation();        }    }}/** * Move the scrolled position of your view. This will cause a call to * {@link #onScrollChanged(int, int, int, int)} and the view will be * invalidated. * @param x the amount of pixels to scroll by horizontally * @param y the amount of pixels to scroll by vertically */public void scrollBy( int x, int y) {    scrollTo( mScrollX + x, mScrollY + y);}

从中可以看出,scrollBy实际上也是调用scrollTo方法,它实现了基于当前位置的相对滑动,scrollTo实现了基于所传递参数的绝对滑动。

图示
这里写图片描述
mScrollX和mScrollY的改变规则:
1.这两个属性可以通过getScrollX和getScrollY得到;
2.mScrollX的值总是等于view左边缘和view内容左边缘在水平方向上的距离;
3.mScrollY的值总是等于view上边缘和view内容上边缘在竖直方向上的距离;
4.view边缘指view的位置,由四个顶点组成,view内容边缘指view中内容的边
缘,scrollTo和scrollBy只改变view内容的位置,而不能改变view在布局中的位置。
5.mScrollX和mScrollY的单位为像素,并且当view的左边缘在view内容的左边缘
的右边时,mScrollX为正值,反之为负值;
6.当view的上边缘在view内容的上边缘的下边时,mScrollX为正值,反之为负值。

也就是说:
从左向右滑动,mScrollX为负值,从上往下滑动mScrollY为负值。

(2)使用动画
采用view动画,将一个view在100ms内,从原位置向右下角移动100个像素。

0 0