PagedView.java 是launcher的页面抽象类,桌面和all app界面都继承了该类
launcher 的点击、滑动事件的处理主要有两个方法
onInterceptTouchEvent(MotionEvent ev) 和 onTouchEvent(MotionEvent ev)
这个两个方法的事件处理的调用分析 可以参考 这两篇文章
http://www.blogjava.net/TiGERTiAN/archive/2011/02/22/344869.html
http://blog.csdn.net/android_tutor/article/details/7193090
根据打印的log分析,launcher中分别执行点击和滑动时这个两个方法调用关系
1.在launcher的桌面和all app界面 执行点击事件的时候,
若onInterceptTouchEvent方法 return false,则不会进入 onTouchEvent事件中,onInterceptTouchEvent会执行多次包括 ACTION_DOWN,ACTION_MOVE,ACTION_UP的事件;
若onInterceptTouchEvent方法 return true,则会进入 onTouchEvent事件中,onInterceptTouchEvent只会执行一次ACTION_DOWN而onTouchEvent会执行多次包括上面的ACTION_DOWN,ACTION_MOVE,ACTION_UP的事件;
2.在launcher的桌面和all app界面 执行滑动事件的时候
若onInterceptTouchEvent方法 return false,则不会进入 onTouchEvent事件中,onInterceptTouchEvent会执行多次包括 ACTION_DOWN,ACTION_MOVE,ACTION_UP的事件;
若onInterceptTouchEvent方法 return true,则会进入 onTouchEvent事件中,onInterceptTouchEvent只会执行一次本次ACTION_MOVE而onTouchEvent会执行多次包括上面的ACTION_DOWN,ACTION_MOVE,ACTION_UP的事件;
------------------------------------------------------滑动一次log-----------------------------
01-01 13:22:34.680: I/lilei(8839): onInterceptTouchEvent___222__return:false action:0 mTouchState:0
01-01 13:22:34.710: I/lilei(8839): _______onTouchEvent____
01-01 13:22:34.710: I/lilei(8839): _______onTouchEvent____action:2
01-01 13:22:34.710: I/lilei(8839): _______onTouchEvent___return_____
01-01 13:22:34.710: I/lilei(8839): onInterceptTouchEvent___222__return:true action:2 mTouchState:1
01-01 13:22:34.750: I/lilei(8839): _______onTouchEvent____
01-01 13:22:34.750: I/lilei(8839): _______onTouchEvent____action:2
01-01 13:22:34.750: I/lilei(8839): _______onTouchEvent___return_____
01-01 13:22:34.780: I/lilei(8839): _______onTouchEvent____
01-01 13:22:34.780: I/lilei(8839): _______onTouchEvent____action:2
01-01 13:22:34.780: I/lilei(8839): _______onTouchEvent___return_____
01-01 13:22:34.790: I/lilei(8839): _______onTouchEvent____
01-01 13:22:34.790: I/lilei(8839): _______onTouchEvent____action:2
01-01 13:22:34.790: I/lilei(8839): _______onTouchEvent___return_____
01-01 13:22:34.800: I/lilei(8839): _______onTouchEvent____
01-01 13:22:34.800: I/lilei(8839): _______onTouchEvent____action:1
01-01 13:22:34.800: I/lilei(8839): _______onTouchEvent___return_____
根据打印的log launcher 界面滑动一次看下代码代码调用流程
1.首先调用onInterceptTouchEvent在的ACTION_DOWN事件 return false,
MotionEvent.ACTION_DOWN做了那些操作呢?
final int xDist = Math.abs(mScroller.getFinalX() - mScroller.getCurrX());
final boolean finishedScrolling = (mScroller.isFinished() || xDist < mTouchSlop);
if (finishedScrolling) {
mTouchState = TOUCH_STATE_REST;
mScroller.abortAnimation();
} else {
mTouchState = TOUCH_STATE_SCROLLING;
}
mScroller.getFinalX()是当前屏幕所在的位置(0,480,960..)和mScroller.getCurrX()当前滚动的位置
若上个滚动结束,则设置mTouchState = TOUCH_STATE_REST并中断滚动动画,否则将状态设置为滚动状态mTouchState = TOUCH_STATE_SCROLLING
2.由于上面的onInterceptTouchEvent 返回的是false
下面会执行onInterceptTouchEvent的ACTION_MOVE事件 return true;
MotionEvent.ACTION_MOVE做了那些操作
if (mActivePointerId != INVALID_POINTER) {
//Fix Bug 191024, launcher optimize
float lastMotionX = mLastMotionX;
determineScrollingStart(ev);
if (mTouchState == TOUCH_STATE_SCROLLING)
{
mLastMotionX = lastMotionX;
onTouchEvent(ev);
}
//Fix Bug 191024, launcher optimize
break;
}
MotionEvent.ACTION_MOVE 调用了determineScrollingStart(ev)方法,
该方法设置 状态mTouchState设置为TOUCH_STATE_SCROLLING,showScrollingIndicator显示页面指示条,取消当前页面长按事件等操作
3.由于上面的onInterceptTouchEvent 返回的是true,
下面会调用onTouchEvent的ACTION_MOVE事件,后面只会调用onTouchEvent的事件
onTouchEvent的MotionEvent.ACTION_MOVE做了那些操作
if (mTouchState == TOUCH_STATE_SCROLLING) {
// Scroll to follow the motion event
final int pointerIndex = ev.findPointerIndex(mActivePointerId);
final float x = ev.getX(pointerIndex);
final float deltaX = mLastMotionX + mLastMotionXRemainder - x;
mTotalMotionX += Math.abs(deltaX);
// Only scroll and update mLastMotionX if we have moved some discrete amount. We
// keep the remainder because we are actually testing if we've moved from the last
// scrolled position (which is discrete).
if (Math.abs(deltaX) >= SCROLL_DISTANCE) { //Fix Bug 191024, launcher optimize
mTouchX += deltaX;
mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
if (!mDeferScrollUpdate) {
Log.i("lilei", "scrollBy:"+(int) deltaX+" deltaX:"+deltaX);
scrollBy((int) deltaX, 0);
if (DEBUG) Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
} else {
//invalidate(); //Fix Bug 191024, launcher optimize
}
mLastMotionX = x;
mLastMotionXRemainder = deltaX - (int) deltaX;
} else {
awakenScrollBars();
}
} else {
determineScrollingStart(ev);
}
若两次ACTION_MOVE之间移动距离deltaX大于最小移动单位,则调用scrollBy((int) deltaX, 0),让launcher界面移动手指移动距离
4.当手指离开launcher界面时,会调用onTouchEvent的ACTION_UP事件
if (mTouchState == TOUCH_STATE_SCROLLING) {
final int activePointerId = mActivePointerId;
final int pointerIndex = ev.findPointerIndex(activePointerId);
final float x = ev.getX(pointerIndex);
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
final int deltaX = (int) (x - mDownMotionX);
final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
SIGNIFICANT_MOVE_THRESHOLD;
mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);
boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING &&
Math.abs(velocityX) > mFlingThresholdVelocity;
// In the case that the page is moved far to one direction and then is flung
// in the opposite direction, we use a threshold to determine whether we should
// just return to the starting page, or if we should skip one further.
boolean returnToOriginalPage = false;
if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD &&
Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
returnToOriginalPage = true;
}
int finalPage;
// We give flings precedence over large moves, which is why we short-circuit our
// test for a large move if a fling has been registered. That is, a large
// move to the left and fling to the right will register as a fling to the right.
if (((isSignificantMove && deltaX > 0 && !isFling) ||
(isFling && velocityX > 0)) && mCurrentPage > (Launcher.CYCLE_SLIP ? -1 : 0)) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
snapToPageWithVelocity(finalPage, velocityX);
} else if (((isSignificantMove && deltaX < 0 && !isFling) ||
(isFling && velocityX < 0)) &&
mCurrentPage < (Launcher.CYCLE_SLIP ? getChildCount() : getChildCount() - 1)) {
finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
snapToPageWithVelocity(finalPage, velocityX);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
// we can just page
int nextPage = Math.max(0, mCurrentPage - 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
// at this point we have not moved beyond the touch slop
// (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
// we can just page
int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
if (nextPage != mCurrentPage) {
snapToPage(nextPage);
} else {
snapToDestination();
}
} else {
onUnhandledTap(ev);
}
mTouchState = TOUCH_STATE_REST;
mActivePointerId = INVALID_POINTER;
releaseVelocityTracker();
-------------------------------------------
当手指离开launcher界面的时候是否切换屏幕的条件是 快速滑动isFling 或慢速滑动并且移动距离大于屏幕宽带的0.4倍(具体看代码参数变量的值)
调用snapToPageWithVelocity()方法切换页面
未完待续..