主要总结一下使用手势相关的代码逻辑。主要是单点拖动,多点拖动,fling和OveScroll的实现。每个手势都会有代码片段。
为了节约你的时间,我特地将文章大致内容总结如下:
手势Drag的实现和原理
手势Fling的实现和原理
OverScroll效果和EdgeEffect效果的实现和原理。
Drag
Drag是最为基本的手势:用户可以使用手指在屏幕上滑动,以拖动屏幕相应内容移动。实现Drag手势其实很简单,步骤如下:
在ACTION_DOWN事件发生时,调用getX和getY函数获得事件发生的x,y坐标值,并记录在mLastX和mLastY变量中。
在ACTION_MOVE事件发生时,调用getX和getY函数获得事件发生的x,y坐标值,将其与mLastX和mLastY比较,如果二者差值大于一定限制(ScaledTouchSlop),就执行scrollBy函数,进行滚动,最后更新mLastX和mLastY的值。
在ACTION_UP和ACTION_CANCEL事件发生时,清空mLastX,mLastY。
@Override
public boolean onTouchEvent(MotionEvent event) {
int actionId = MotionEventCompat.getActionMasked(event);
switch (actionId) {
case MotionEvent.ACTION_DOWN:
mLastX = event.getX();
mLastY = event.getY();
mIsBeingDragged = true;
if (getParent() != null) {
getParent().requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_MOVE:
float curX = event.getX();
float curY = event.getY();
int deltaX = (int) (mLastX - curX);
int deltaY = (int) (mLastY - curY);
if (!mIsBeingDragged && (Math.abs(deltaX)> mTouchSlop ||
Math.abs(deltaY)> mTouchSlop)) {
mIsBeingDragged = true;
// 让第一次滑动的距离和之后的距离不至于差距太大
// 因为第一次必须>TouchSlop,之后则是直接滑动
if (deltaX > 0) {
deltaX -= mTouchSlop;
} else {
deltaX += mTouchSlop;
}
if (deltaY > 0) {
deltaY -= mTouchSlop;
} else {
deltaY += mTouchSlop;
}
}
// 当mIsBeingDragged为true时,就不用判断> touchSlopg啦,不然会导致滚动是一段一段的
// 不是很连续
if (mIsBeingDragged) {
scrollBy(deltaX, deltaY);
mLastX = curX;
mLastY = curY;
}
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mIsBeingDragged = false;
mLastY = 0;
mLastX = 0;
break;
default:
}
return mIsBeingDragged;
}
多触点Drag
上边的代码只适用于单点触控的手势,如果你是两个手指触摸屏幕,那么它只会根据你第一个手指滑动的情况来进行屏幕滚动。更为致命的是,当你先松开第一个手指时,由于我们少监听了ACTION_POINTER_UP事件,将会导致屏幕突然滚动一大段距离,因为第二个手指移动事件的x,y值会和第一个手指移动时留下的mLastX和mLastY比较,导致屏幕滚动。
如果我们要监听并处理多触点的事件,我们还需要对ACTION_POINTER_DOWN和ACTION_POINTER_UP事件进行监听,并且在ACTION_MOVE事件时,要记录所有触摸点事件发生的x,y值。
当ACTION_POINTER_DOWN事件发生时,我们要记录第二触摸点事件发生的x,y值为mSecondaryLastX和mSecondaryLastY,和第二触摸点pointer的id为mSecondaryPointerId