
ListView的滑动是通过ListView的触摸事件引起的,ListView继承自AbsListView,AbsListView继承了ViewGroup,通过ViewGroup对触摸事件的分配流程来看,在调用onTouchEvent方法之前,会先调用ViewGroup的onInterceptTouchEvent方法来判断是否在将触摸事件分配给子视图onTouchEvent方法之前,进行拦截。
因此,ListView滑动流程的开始方法就是AbsListView中的onInterceptTouchEvent方法。
一个触摸事件的开始肯定是down,接下来我们看看onInterceptTouchEvent中的down手势事件处理的源代码:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int actionMasked = ev.getActionMasked();
View v;
...
switch (actionMasked) {
case MotionEvent.ACTION_DOWN: {
int touchMode = mTouchMode;
if (touchMode == TOUCH_MODE_OVERFLING || touchMode == TOUCH_MODE_OVERSCROLL) {
mMotionCorrection = 0;//开始滚动之前,手指移动的距离
return true;
}
final int x = (int) ev.getX();
final int y = (int) ev.getY();
mActivePointerId = ev.getPointerId(0);
int motionPosition = findMotionRow(y);//获取手指按住的这个子视图对应的item在适配器中的位置
if (touchMode != TOUCH_MODE_FLING && motionPosition >= 0) {
// User clicked on an actual view (and was not stopping a fling).
// Remember where the motion event started
v = getChildAt(motionPosition - mFirstPosition);
mMotionViewOriginalTop = v.getTop();
mMotionX = x;
mMotionY = y;
mMotionPosition = motionPosition;
mTouchMode = TOUCH_MODE_DOWN;
clearScrollingCache();
}
mLastY = Integer.MIN_VALUE;
initOrResetVelocityTracker();
mVelocityTracker.addMovement(ev);
mNestedYOffset = 0;
startNestedScroll(SCROLL_AXIS_VERTICAL);
if (touchMode == TOUCH_MODE_FLING) {
return true;
}
break;
}
case MotionEvent.ACTION_MOVE: {
switch (mTouchMode) {
case TOUCH_MODE_DOWN:
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == -1) {
pointerIndex = 0;
mActivePointerId = ev.getPointerId(pointerIndex);
}
final int y = (int) ev.getY(pointerIndex);
initVelocityTrackerIfNotExists();
mVelocityTracker.addMovement(ev);
if (startScrollIfNeeded((int) ev.getX(pointerIndex), y, null)) {
return true;
}
break;
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
mTouchMode = TOUCH_MODE_REST;
mActivePointerId = INVALID_POINTER;
recycleVelocityTracker();
reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
stopNestedScroll();
break;
}
case MotionEvent.ACTION_POINTER_UP: {
onSecondaryPointerUp(ev);
break;
}
}
return false;
}
上述代码的解释:
mTouchMode的值可为:
- TOUCH_MODE_REST:未处于滚动机制之中;
- TOUCH_MODE_DOWN:接收到down触摸事件,但还没有达到轻触的程度;
- TOUCH_MODE_TAP: 触摸事件被标识为轻触事件(轻触Runnable已经执行),且等待一个长按事件;
- TOUCH_MODE_DONE_WAITING:仍为down事件的范畴,等待手指开始移动(即等待move触摸事件的发生);
- TOUCH_MODE_SCROLL:ListView内容随着指尖的移动而移动,此时已经进入move触摸事件之中了;
- TOUCH_MODE_FLING:ListView进入抛动模式,滑动速度过快,手指离开屏幕后,ListView会继续滑动;
- TOUCH_MODE_OVERSCROLL:滑动到ListView边缘的状态;
- TOUCH_MODE_OVERFLING:抛动回弹,抛动到ListView边缘的状态;
网友评论