View的基础知识
1.什么是View
View是Android中所有控件的基类,不管Button和TextView还是RelativeLayout和ListView他们共同的基类都是View。还有ViewGroup,包含多个控件,其实ViewGroup也继承了View,这就意味着View本身就可以是单个控件也可以是由多个控件组成的一组控件。
2.View的位置参数
View的位置主要由它的四个顶点来决定,分别对应于View的四个属性:top、left、right、bottom,其中top是左上角纵坐标,left是左上角横坐标,right是右下角横坐标,bottom是右下角纵坐标。
所以View的四个角坐标为左上角(left,top)右上角(right,top)左下角(left,bottom)右下角(right,bottom)在Android中x轴和y轴的正方向分别为右和下。
所以View的宽高和坐标的关系:
width = right - left
height = bottom - top
View的这四个参数获取方法:
int Left = view.getLeft();
int Right = view.getRight();
int Top = view.getRight();
int Bottom = view.getBottom();
从Android3.0开始View增加了额外的几个参数:
x、y、translationX、translationY。
其中x和y是View左上角的坐标,而translationX、translationY是View左上角相对于父容器的偏移量。这几个参数也是相对于父容器的坐标,并且translationX、translationY的默认值是0,和View的四个基本的位置参数一样,View也为他们提供了get/set方法,这几个参数的换算关系如下所示:
x = left + translationX
y = top + translationY
要注意,View在平移过程中,top和left表示的是原始左上角的位置信息,其值不会发生改变,此时发生改变的是x、y、translationX、translationY这四个参数。
3.MotionEvent和TouchSlope
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坐标,而getRawX/getRawY
返回的是相对于手机屏幕左上角的x和y坐标。
TouchSlope
TouchSlope是系统所能识别出的被认为是滑动的最小距离,也就是说当滑动的的距离小于这个常亮那么系统就不认为你是在进行滑动操作获得这个常亮的方法:
int slop = ViewConfiguration.get(context).getScaledTouchSlop();
4.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(1000);
第二这里的速度是指一段时间内手指所划过的像素数,那么比如讲时间间隔设为1000ms,在1S内手指在水平方向从左向右画过100px,那么水平速度就是100。注意 速度可以为负数,当手指从右往左滑动式,水平方向速度即为负值公式如下:
速度 = (终点位置 - 起点位置)/ 时间段
computeCurrentVelocity(1000)这个方法中的参数表示一个时间间隔,它的单位是毫秒ms。
最后,当不需要使用它的时候,需要调用clear方法来重置并回收内存;
velocitytracker.clear();
velocitytracker.recycle();
GestureDetector
手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为,使用参考如下:
首先创建一个GestureDetector对象,实现OnGestureListener接口
OnGestureListener listener = new OnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
//手指(轻轻触屏后)松开,
//伴随着一个MotionEvent ACTION_UP而触发,这是单击行为
return false;
}
@Override
public void onShowPress(MotionEvent e) {
//手指轻轻触摸屏幕,尚未松开或拖动,由1个ACTION_DOWN触发
//*注意和onDown()的区别,他强调的是没有松开或者拖动的状态
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//手指按下屏幕并拖动,由1个ACTION_DOWN,多个ACTION_MOVE触发
//这是拖动行为
return false;
}
@Override
public void onLongPress(MotionEvent e) {
//用户长久地按着屏幕不放,即长按
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
//用户按下触摸屏、快速滑动后松开
//由1个ACTION_DOWN、多个ACTION_MOVE和1个ACTION_UP触发
//这是快速滑动行为
return false;
}
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
//手指轻轻触碰屏幕的一瞬间,由1个ACTION_DOWN触发
return false;
}
});
GestureDetector mGestureDetector = new GestureDetector(getContext(), listener);
//解决长按屏幕后无法拖动的现象
mGestureDetector.setIsLongpressEnabled(false);
除了OnGestureListener
还有 OnDoubleTapListener
接口
mGestureDetector.setOnDoubleTapListener(doubleTapListener);
OnDoubleTapListener doubleTapListener = new OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
// 严格的单击行为
//* 注意他和onSingleTapUp的区别,如果触发了onSingleTapConfirmed,那么后面不可能在紧跟着另一个单击行为,即这只可能是单击,而不可能是双击中的一次单击
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
// 表示发生了双击行为,在双击的期间,ACTION_DOWN、ACTION_MOVE和ACTION_UP都会触发此回调
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
// 双击,由2次连续的单击组成
//他不可能和onSingleTapConfirmed共存
return false;
}
};
mGestureDetector.setOnDoubleTapListener(doubleTapListener);
日常开发中可以不适用GestureDetector,完全可以自己再View的onTouchEvent方法中实现所有所需的监听,这个就看个人喜好了。建议是:如果只是监听滑动相关的,建议自己在onTouchEvent中实现,如果要监听双击这种行为的话,那么使用GestureDetector。
5.Scroller
弹性滑动对像,用于实现View的弹性滑动。Scroller本身无法让View弹性滑动,他需要和View的computesScroll方法配合是用才能完全完成这个功能
Scroller mScroller = new Scroller(getContext());
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int deltaX = destX - scrollX;
// 1000ms内滑向destX,效果就是慢慢滑动
mScroller.startScroll(scrollX, 0, deltaX, 0);
invalidate();
}
@Override
public void computeScroll() {
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
super.computeScroll();
}