View的位置参数
由四个顶点决定:
top:左上角的纵坐标, Top = getTop();
left:左上角的横坐标, Left = getLeft();
bottom:右下角的纵坐标, Bottom = getBottom();
right:右下角的横坐标, Right = getRight();
需要注意的是,这些坐标都是相对于View的父容器来说的,因此是一种相对坐标。
可以得到View的宽高和坐标的关系:
width = right - left
height = bottom - top
在Android3.0之后,增加了几个额外的参:x,y,translationX,translation,其中x和y是View左上角的坐标,而translationX和translationY是View的偏移量,默认值都是0.
需要注意的是,这几个参数同样是相对于View的父容器而言的。同样也有get/set()方法。其换算的关系为:x = left + translationX , y = top + translationY
还有一点要注意的就是:View在平移的过程中,top和left是相对于原始View的坐标位置,是不会改变的,平移改变的是x,y,translationX和translationY的值
MotionEvent和TouchSlop
- MotionEvent
不再重复,其中需要注意的一点就是我们可以通过MotionEvent对象获取点击事件发生的x和y的坐标,提供了两组方法,getX(),getY()和getRawX()/getRawY()。其中getX()/getY()获取的是相对于当前View的左上角的x和y的坐标(也就是原点是当前View的左上角),而getRawX()/getRawY()获取的是相对于屏幕的x和y的坐标。
TouchSlop
含义:TouchSlop是系统所能识别的被认为是最小的滑动距离。小于这个距离,系统就不认为你是在滑动。
注意:这是一个常量,和设备有关,在不同设备上的值可能是不同的。
获取方式:ViewConfiguration.get(getContext()) .getScaledTouchSlop()源码中的定义: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>
VelocityTracker、GestureDetector和Scroller
1.VelocityTracker
含义:速度追踪,用于追踪手指在滑动过程中的速度,包括水平和垂直方向的速度。
使用:首先在onTouch()方法中追踪当前点击事件的速度。
mButton.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
return false;
}
});
接着,采用如下方式获取速度:
// 获取当前的速度
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
这里有两点需要注意的:
1.获取速度之前必须先计算速度,及之前必须调用computeCurrentVelocity方法;
2.这里的速度是指一段时间内手指滑过的像素数,computeCurrentVelocity方法接收的参数就是时间间隔,单位是毫秒。
注意速度可以为负值,当手指从右往左滑动的时候,水平速度即为负值。 速度 = (终点位置 - 起始位置) / 时间段
最后,当不需要使用它的时候,需要调用clear方法重置并回收内存。
// 重置并回收内存
velocityTracker.clear();
velocityTracker.recycle();
2.GestureDetector
含义:手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。
使用:需要创建一个GestureDetector对象并实现OnGestureListener接口,根据需要我们还可以实现OnDoubleTapListener监听双击事件。
但是在使用的过程中发现GestureDetector已经显示过时,而是用V4包中的GestureDetectorCompat来代替,官方是这么解释的:
Detects various gestures and events using the supplied MotionEvents. The GestureDetector.OnGestureListener callback will notify users when a particular motion event has occurred. This class should only be used with MotionEvents reported via touch (don't use for trackball events).
This compatibility implementation of the framework's GestureDetector guarantees the newer focal point scrolling behavior from Jellybean MR1 on all platform versions.
那GestureDetectorCompat怎么使用呢?
1.为View创建GestureDetectorCompat对象。
2.在待监听的View的ouTouchEvent方法中实现GestureDetectorCompat的onTouchEvent方法。
创建GestureDetectorCompat需要实现GestureDetector.OnGestureListener接口,但是该接口中的方法好多有时候并不需要实现这么多。
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
还好你可以通过实现GestureDetector.SimpleOnGestureListener接口,需要什么方法就去实现什么方发即可。
3.Scroller
含义:弹性滑动对象,用于实现View的弹性滑动。(弹性滑动即有过渡效果的滑动,其过程不是瞬间完成的,用户体验更佳)
使用:Scroller本身无法让View弹性滑动,需要和View的computeScroll方法配合使用。
典型代码是固定的,如下所示:
private Scroller mScroller = new Scroller(mContext);
/**
* 缓慢移动到指定位置
* @param destX 指定位置x坐标
* @param destY 指定位置y坐标
*/
private void smoothScrollTo(int destX, int destY) {
int scrollerX = getScrollX();
int deltaX = destX - scrollerX;
// 1000ms内滑向destX
mScroller.startScroll(scrollerX,0,deltaX,0,1000);
invalidate();
}
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
关于Scroller的工作原理,可以参照下一篇博客。