launcher 点击和滑动屏幕过程分析

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()方法切换页面

 

未完待续..

posted @ 2013-08-27 15:55  adam.li  阅读(1936)  评论(0编辑  收藏  举报