下面主要说一些 View 的基础知识,从而为后面更好的理解 View 做铺垫。
主要内容有: View 的位置参数、 MotionEvent 和 TouchSlop 对象、VelocityTracker、GestureDetector 和 Scroller 对象。
下面来了解一些这些基础的概念吧。(部分内容摘自Android开发艺术探索)
1. View 的位置参数
View 的位置主要是由它的四个定点来决定,分别对应 View 的四个属性:top、left、right、bottom。
top:左上角纵坐标;bottom:右下角纵坐标;
left:左上角横坐标;right:右下角横坐标;
为了方便理解做了一张图:
从图中,可以清楚看出 View 的宽高:
width = right - left
height = bottom - top
了解到这里,那么这四个参数是如何得到的呢?如果看过源码,那么就能轻易的看到获取方式,如下:
left = getLeft();
right = getRight();
top = getTop();
bottom = getBottom();
2. MotionEvent 和 TouchSlop 对象
先看第一个参数: MotionEvent ( 触摸事件 )
当我们的手指接触屏幕后,会产生一系列的事件,比较常用的有下面几种:
ACTION_DOWN 手指刚接触屏幕
ACTION_MOVE 手指在屏幕移动
ACTION_UP 手指从屏幕松开
这三种相信都不陌生,当我们手指接触屏幕,然后再屏幕滑动一会再松开,会经历这么一个过程:
DOWN ==> MOVE ==> ... MOVE ==> UP
同时我们可以通过 MotionEvent 对象获取点击事件发生的 x 和 y 坐标。系统为我们提供了两组方法:
getX()/get()Y:相对于当前 View 左上角的 x 和 y 坐标;
getRawX()/getRawY():相对于手机屏幕左上角的 x 和 y 坐标;
再看另一个参数:TouchSlop (最小距离)
TouchSlop 是系统所能识别出的被认为是滑动的最小距离;
也就是说,当手指在屏幕滑动时,如果两次滑动间的距离小于这个值,那么系统不认为这是一次滑动操作;手机不同这个值也是不同的。
通过下面的方式便可以获取这个常量:
ViewConfiguration.get(getContext()).getScaledTouchSlop()
3. VelocityTracker ( 速度跟踪器 )
VelocityTracker 用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。
来看一下它的使用步骤:
//1.初始化 VelocityTracker 对象:
VelocityTracker mVelocityTracker = VelocityTracker.obtain();
//2.添加追踪:
mVelocityTracker.addMovement(event);
//3.计算速度:
//computeCurrentVelocity 第一个参数:时间为一秒,第二个参数:一秒运动了多少个像素
verTracker.computeCurrentVelocity(1000, ViewConfiguration.get(this).getMaximumFlingVelocity());
float velocityX = verTracker.getXVelocity(oneId);
float velocityY = verTracker.getYVelocity(oneId);
//4.回收:
mVelocityTracker.clear();
mVelocityTracker.recycle();
这里要理解速度的计算方法:
速度 = ( 终点位置 - 起点位置 ) / 时间段
了解使用步骤后,来看一下实际应用,就直接上代码了:
public class MainActivity extends AppCompatActivity {
private VelocityTracker mVelocityTracker;//速度追踪器
private int oneId;//第一个接触点id
private static final String sFormatStr = "velocityX=%f\nvelocityY=%f";//格式化类型
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
/**
* 1.初始化 VelocityTracker 对象
*/
if (null == mVelocityTracker) {
mVelocityTracker = VelocityTracker.obtain();
}
/**
* 2.添加追踪
*/
mVelocityTracker.addMovement(event);
final VelocityTracker verTracker = mVelocityTracker;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//求第一个触点的id,可能有多个触点,但至少一个
oneId = event.getPointerId(0);
break;
case MotionEvent.ACTION_MOVE:
/**
* 3.计算速度
*/
//第一个参数:时间为一秒,第二个参数:一秒运动了多少个像素
verTracker.computeCurrentVelocity(1000, ViewConfiguration.get(this).getMaximumFlingVelocity());
float velocityX = verTracker.getXVelocity(oneId);
float velocityY = verTracker.getYVelocity(oneId);
//格式化数据
String info = String.format(sFormatStr, velocityX, velocityY);
Log.e("=====速度为", info + "");
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
/**
* 4.回收
*/
if (mVelocityTracker != null) {
mVelocityTracker.clear();
mVelocityTracker.recycle();
mVelocityTracker = null;
}
break;
default:
break;
}
return super.onTouchEvent(event);
}
}
上面就是使用 VelocityTracker 的全过程。
4. GestureDetector ( 手势检测器 )
GestureDetector 是辅助检测用户的点击、滑动、长按、双击等行为。
下面说一下使用方法:
//1.初始化对象
private GestureDetector mGestureDetector;
mGestureDetector = new GestureDetector(new gestureListener());
mGestureDetector.setOnDoubleTapListener(new doubleTapListener());
//2.监听onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event) {
return mGestureDetector.onTouchEvent(event);
}
使用步骤非常简单,下面来看一下具体的使用方法:
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
private GestureDetector mGestureDetector;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mGestureDetector = new GestureDetector(new gestureListener());
mGestureDetector.setOnDoubleTapListener(new doubleTapListener());
//屏蔽了长按功能,使长按可以触发拖动效果;否则长按时不可以触发拖动效果
mGestureDetector.setIsLongpressEnabled(false);
TextView textView = findViewById(R.id.tv);
textView.setOnTouchListener(this);
textView.setFocusable(true);
textView.setClickable(true);
textView.setLongClickable(true);
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return mGestureDetector.onTouchEvent(motionEvent);
}
//OnGestureListener监听
private class gestureListener implements GestureDetector.OnGestureListener {
@Override
public boolean onDown(MotionEvent motionEvent) {
Log.e("=====gestureListener", "按下");
return false;
}
@Override
public void onShowPress(MotionEvent motionEvent) {
Log.e("=====gestureListener", "按下,未松开和未拖动");
}
@Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
Log.e("=====gestureListener", "单击");
return false;
}
@Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
Log.e("=====gestureListener", "拖动");
return false;
}
@Override
public void onLongPress(MotionEvent motionEvent) {
Log.e("=====gestureListener", "长按");
}
@Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
Log.e("=====gestureListener", "快速滑动");
return false;
}
}
//OnDoubleTapListener监听
private class doubleTapListener implements GestureDetector.OnDoubleTapListener {
public boolean onSingleTapConfirmed(MotionEvent e) {
//如果触发此方法,后面就不可以再紧跟一个单击
Log.e("=====doubleTapListener", "单击");
return true;
}
public boolean onDoubleTap(MotionEvent e) {
Log.e("=====doubleTapListener", "两次连续单击");
return true;
}
public boolean onDoubleTapEvent(MotionEvent e) {
Log.e("=====doubleTapListener", "双击");
return true;
}
}
}
这样便实现了对 TextView 控件的监听,可以看到上面的方法很多,比较常用的方法有五个:
onSingleTapUp (单击)、onFling (快速滑动)、onScroll(拖动)、onLongPress (长按)、onDoubleTapEvent (双击)。
5. Scroller ( 弹性滑动对象 )
Scroller 用于实现 View 的弹性滑动。
那么如何实现弹性滑动呢?很多地方都给出下面的经典代码:
Scroller mScroller;
mScroller = new Scroller(context);
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
postInvalidate();
}
}
private void smoothScrollTo(int destX, int destY) {
int scrollX = getScrollX();
int delta = destX - scrollX;
mScroller.startScroll(scrollX, 0, delta, 0, 100);
invalidate();
}
在这里我也先给出经典的代码,想了解滑动的可以看这一篇:View的滑动。