Android_ListView_onTouchEvent源码分析

来源:互联网 发布:2017安全知识网络大赛 编辑:程序博客网 时间:2024/04/30 21:07

Android ListView  onTouchEvent源码简单分析,在看代码之前先来看下代码结构图


1.onTouchEvent源码

    @Override    public boolean onTouchEvent(MotionEvent ev) {        if (!isEnabled()) {            // A disabled view that is clickable still consumes the touch            // events, it just doesn't respond to them.            return isClickable() || isLongClickable();        }               // AbsListView 绘制与控制手指快速滚动的辅助类        if (mFastScroller != null) {            boolean intercepted = mFastScroller.onTouchEvent(ev);            if (intercepted) {                return true;            }        }        final int action = ev.getAction();        View v;        int deltaY;         // 获取触摸滚动时的速率        if (mVelocityTracker == null) {            mVelocityTracker = VelocityTracker.obtain();        }        mVelocityTracker.addMovement(ev);        // ListView触屏事件主要从ACTION操作划分        switch (action & MotionEvent.ACTION_MASK) {        case MotionEvent.ACTION_DOWN: {             ......             break;        }        case MotionEvent.ACTION_MOVE: {            ......            break;        }        case MotionEvent.ACTION_UP: {            switch (mTouchMode) {            case TOUCH_MODE_DOWN:            case TOUCH_MODE_TAP:            case TOUCH_MODE_DONE_WAITING:                ......                mTouchMode = TOUCH_MODE_REST;                break;            case TOUCH_MODE_SCROLL:             ......                break;            }            setPressed(false);            // Need to redraw since we probably aren't drawing the selector anymore            invalidate();            final Handler handler = getHandler();            if (handler != null) {                handler.removeCallbacks(mPendingCheckForLongPress);            }            if (mVelocityTracker != null) {                mVelocityTracker.recycle();                mVelocityTracker = null;            }                       mActivePointerId = INVALID_POINTER;            if (PROFILE_SCROLLING) {                if (mScrollProfilingStarted) {                    Debug.stopMethodTracing();                    mScrollProfilingStarted = false;                }            }            break;        }        case MotionEvent.ACTION_CANCEL: {            mTouchMode = TOUCH_MODE_REST;            ......            break;        }               case MotionEvent.ACTION_POINTER_UP: {            ......            break;        }               }        return true;    }

2.ACTION_DOWN,主要是CheckForTap

        case MotionEvent.ACTION_DOWN: {            mActivePointerId = ev.getPointerId(0);            final int x = (int) ev.getX();            final int y = (int) ev.getY();                        // 手指按下时x,y坐标,获取当前选中的item            int motionPosition = pointToPosition(x, y);            // 如果ListView 数据未发生变化            if (!mDataChanged) {                if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)                        && (getAdapter().isEnabled(motionPosition))) {                    // User clicked on an actual view (and was not stopping a fling). It might be a                    // click or a scroll. Assume it is a click until proven otherwise                    mTouchMode = TOUCH_MODE_DOWN;                                       // TAP机制,主要是用于去除手指点击抖动                    // 使Item处于按下状态                    if (mPendingCheckForTap == null) {                        mPendingCheckForTap = new CheckForTap();                    }                    // 添加到消息队列并延时ViewConfiguration.getTapTimeout()执行此runnable                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());                } else {                    if (ev.getEdgeFlags() != 0 && motionPosition < 0) {                        // If we couldn't find a view to click on, but the down event was touching                        // the edge, we will bail out and try again. This allows the edge correcting                        // code in ViewRoot to try to find a nearby view to select                        return false;                    }                      // 之前处于Fling模式                    if (mTouchMode == TOUCH_MODE_FLING) {                        // Stopped a fling. It is a scroll.                        createScrollingCache();                        // 更改为scroll                        mTouchMode = TOUCH_MODE_SCROLL;                        mMotionCorrection = 0;                        motionPosition = findMotionRow(y);                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);                    }                }            }             // 对于ACTION_MOVE,ACTION_UP会使用的触屏位置信息进行记录            if (motionPosition >= 0) {                // Remember where the motion event started                v = getChildAt(motionPosition - mFirstPosition);                mMotionViewOriginalTop = v.getTop();            }            mMotionX = x;            mMotionY = y;            mMotionPosition = motionPosition;            mLastY = Integer.MIN_VALUE;            break;        }

3.ACTION_MOVE,主要是startScrollIfNeeded和trackMotionScroll

        case MotionEvent.ACTION_MOVE: {            final int pointerIndex = ev.findPointerIndex(mActivePointerId);            final int y = (int) ev.getY(pointerIndex);            // 获取y轴当前与前一次的偏移值            deltaY = y - mMotionY;            switch (mTouchMode) {            case TOUCH_MODE_DOWN:            case TOUCH_MODE_TAP:            case TOUCH_MODE_DONE_WAITING:                // 必须移动一段距离后才会执行滚动                startScrollIfNeeded(deltaY);                break;            case TOUCH_MODE_SCROLL:                if (PROFILE_SCROLLING) {                    if (!mScrollProfilingStarted) {                        Debug.startMethodTracing("AbsListViewScroll");                        mScrollProfilingStarted = true;                    }                }                 // 手指移动                if (y != mLastY) {                    deltaY -= mMotionCorrection;                    int incrementalDeltaY = mLastY != Integer.MIN_VALUE ? y - mLastY : deltaY;                                       // No need to do all this work if we're not going to move anyway                    boolean atEdge = false;                    if (incrementalDeltaY != 0) {                      // 滚动的重要方法,滚动的具体处理就是这里                        atEdge = trackMotionScroll(deltaY, incrementalDeltaY);                    }                    // ListView滚动到边界后不不能再进行移动                    if (atEdge && getChildCount() > 0) {                        // Treat this like we're starting a new scroll from the current                        // position. This will let the user start scrolling back into                        // content immediately rather than needing to scroll back to the                        // point where they hit the limit first.                        int motionPosition = findMotionRow(y);                        if (motionPosition >= 0) {                            final View motionView = getChildAt(motionPosition - mFirstPosition);                            mMotionViewOriginalTop = motionView.getTop();                        }                        mMotionY = y;                        mMotionPosition = motionPosition;                        invalidate();                    }                    // 记录当前Y值,用于下次计算偏移量                    mLastY = y;                }                break;            }            break;        }

4.ACTION_UP,主要是PerformClick, mPendingCheckForLongPress, mFlingRunnable

        case MotionEvent.ACTION_UP: {            switch (mTouchMode) {            case TOUCH_MODE_DOWN:            case TOUCH_MODE_TAP:            case TOUCH_MODE_DONE_WAITING:                final int motionPosition = mMotionPosition;                final View child = getChildAt(motionPosition - mFirstPosition);                if (child != null && !child.hasFocusable()) {                    // 清理Item按下状态                    if (mTouchMode != TOUCH_MODE_DOWN) {                        child.setPressed(false);                    }                      // 执行Item Click                    if (mPerformClick == null) {                        mPerformClick = new PerformClick();                    }                    final AbsListView.PerformClick performClick = mPerformClick;                    performClick.mChild = child;                    performClick.mClickMotionPosition = motionPosition;                    performClick.rememberWindowAttachCount();                    mResurrectToPosition = motionPosition;                    if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {                        final Handler handler = getHandler();                        if (handler != null) {                          // 清理tap或者long press长按                            handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ?                                    mPendingCheckForTap : mPendingCheckForLongPress);                        }                        mLayoutMode = LAYOUT_NORMAL;                        if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {                            mTouchMode = TOUCH_MODE_TAP;                            setSelectedPositionInt(mMotionPosition);                            layoutChildren();                            child.setPressed(true);                            positionSelector(child);                            setPressed(true);                            if (mSelector != null) {                                Drawable d = mSelector.getCurrent();                                if (d != null && d instanceof TransitionDrawable) {                                    ((TransitionDrawable) d).resetTransition();                                }                            }                            postDelayed(new Runnable() {                                public void run() {                                    child.setPressed(false);                                    setPressed(false);                                    if (!mDataChanged) {                                        post(performClick);                                    }                                    mTouchMode = TOUCH_MODE_REST;                                }                            }, ViewConfiguration.getPressedStateDuration());                        } else {                            mTouchMode = TOUCH_MODE_REST;                        }                        return true;                    } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {                        post(performClick);                    }                }                mTouchMode = TOUCH_MODE_REST;                break;            case TOUCH_MODE_SCROLL:                final int childCount = getChildCount();                if (childCount > 0) {                    if (mFirstPosition == 0 && getChildAt(0).getTop() >= mListPadding.top &&                            mFirstPosition + childCount < mItemCount &&                            getChildAt(childCount - 1).getBottom() <=                                    getHeight() - mListPadding.bottom) {                        mTouchMode = TOUCH_MODE_REST;                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);                    } else {                        // 是否执行ListView Scroll Fling                        final VelocityTracker velocityTracker = mVelocityTracker;                        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);                        // 获取当前触屏滚动速率                        final int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);                           if (Math.abs(initialVelocity) > mMinimumVelocity) {                            if (mFlingRunnable == null) {                                mFlingRunnable = new FlingRunnable();                            }                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);                                                       // 执行ListView 快速滚动(Scroll Fling)                            mFlingRunnable.start(-initialVelocity);                        } else {                            mTouchMode = TOUCH_MODE_REST;                            reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);                        }                    }                } else {                    mTouchMode = TOUCH_MODE_REST;                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);                }                break;            }            setPressed(false);            // Need to redraw since we probably aren't drawing the selector anymore            invalidate();            final Handler handler = getHandler();            if (handler != null) {                handler.removeCallbacks(mPendingCheckForLongPress);            }            if (mVelocityTracker != null) {                mVelocityTracker.recycle();                mVelocityTracker = null;            }                       mActivePointerId = INVALID_POINTER;            if (PROFILE_SCROLLING) {                if (mScrollProfilingStarted) {                    Debug.stopMethodTracing();                    mScrollProfilingStarted = false;                }            }            break;        }

原创粉丝点击