美文网首页Android面试集锦
ListView的滚动机制

ListView的滚动机制

作者: 谢尔顿 | 来源:发表于2017-09-15 08:32 被阅读21次

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边缘的状态;

相关文章

网友评论

    本文标题:ListView的滚动机制

    本文链接:https://www.haomeiwen.com/subject/zvtssxtx.html