Android NestedScroll dispatchNestedScroll方法参数为什么不是数组

对于NestedScrollView ,支持NestedScrollingChild 和 NestedScrollingParent方法,需要先理解这个内嵌的模式

  • 处理流程
    • 先调用父ViewGroup dispatchNestedPreScroll () 处理需要消耗的距离
    • 再自身调用overScrollByCompat()处理需要消耗的距离
    • 再自身调用dispatchNestedScroll()处理需要消耗的距离
  • dispatchNestedScroll()方法里面的参数int dxConsumed, int dyConsumed, int dxUnconsumed,
    int dyUnconsumed 为什么不是int数组,参考mScrollOffset的使用

重点记录这两个方法,是NestedScrollView的精髓

  • onInterceptTouchEvent

public boolean onInterceptTouchEvent(MotionEvent ev) {

/*

* This method JUST determines whether we want to intercept the motion.

* If we return true, onMotionEvent will be called and we do the actual

* scrolling there.

*/

/*

* Shortcut the most recurring case: the user is in the dragging

* state and he is moving his finger. We want to intercept this

* motion.

*/

  final int action = ev.getAction();
   //如果当前是移动事件,并且   mIsBeingDragged = true,表示正在拖拽,这个时候,直接拦截事件
    //Android 里面有一些都是这么处理,比如disaptchTouchEvent中的mFisrtTarget也是有这方面的处理
  if ((action == MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) {

return true;

  }

switch (action & MotionEvent.ACTION_MASK) {

case MotionEvent.ACTION_MOVE: {

/*

* mIsBeingDragged == false, otherwise the shortcut would have caught it. Check

* whether the user has moved far enough from his original down touch.

*/

/*

* Locally do absolute value. mLastMotionY is set to the y value

* of the down event.

*/

      final int activePointerId =mActivePointerId;
      //这里是还没有获取到出点,只有在 MotionEvent.ACTION_DOWN事件中才能获取到activePointerId
      if (activePointerId ==INVALID_POINTER) {

// If we don't have a valid id, the touch down wasn't on content.

        break;

      }

//需要注意这里的获取当前触点的序号,如果不支持多触点,activePointerId 为MotionEvent对象方法getPointerId里面的第0个节点

final int pointerIndex = ev.findPointerIndex(activePointerId);

      if (pointerIndex == -1) {

Log.e(TAG, "Invalid pointerId=" + activePointerId

+" in onInterceptTouchEvent");

break;

      }

final int y = (int) ev.getY(pointerIndex);

      final int yDiff = Math.abs(y -mLastMotionY);

      if (yDiff >mTouchSlop
          //这里判断是没有与父ViewGroup相关联或者父View没有Y抽的滑动,参考NestedScrollingChildHelper类的startNestedScroll()方法
          //getNestedScrollAxes()返回的是滚动方向
          && (getNestedScrollAxes() & ViewCompat.SCROLL_AXIS_VERTICAL) ==0) {
          //这里会刷新mLastMotionY值,这里很重要,主要注意

mIsBeingDragged =true;

        mLastMotionY = y;

        initVelocityTrackerIfNotExists();

        mVelocityTracker.addMovement(ev);

        mNestedYOffset =0;

        final ViewParent parent = getParent();

        if (parent !=null) {
//父类不拦截
parent.requestDisallowInterceptTouchEvent(true);

        }

}

break;

    }

case MotionEvent.ACTION_DOWN: {

final int y = (int) ev.getY();

      if (!inChild((int) ev.getX(), y)) {

mIsBeingDragged =false;

        recycleVelocityTracker();

break;

      }

/*

* Remember location of down touch.

* ACTION_DOWN always refers to pointer index 0.

*/

      mLastMotionY = y;

      mActivePointerId = ev.getPointerId(0);

      initOrResetVelocityTracker();

      mVelocityTracker.addMovement(ev);

      /*

* If being flinged and user touches the screen, initiate drag;

* otherwise don't. mScroller.isFinished should be false when

* being flinged. We need to call computeScrollOffset() first so that

* isFinished() is correct.

*/

      mScroller.computeScrollOffset();

      mIsBeingDragged = !mScroller.isFinished();
      //开始Y抽内嵌滑动,
      startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);

break;

    }

case MotionEvent.ACTION_CANCEL:

case MotionEvent.ACTION_UP:

/* Release the drag */

      mIsBeingDragged =false;

      mActivePointerId =INVALID_POINTER;

      recycleVelocityTracker();

      if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0, getScrollRange())) {

ViewCompat.postInvalidateOnAnimation(this);

      }
//停止内嵌滑动设置
stopNestedScroll(ViewCompat.TYPE_TOUCH);

break;

    case MotionEvent.ACTION_POINTER_UP:

onSecondaryPointerUp(ev);

break;

  }

/*

* The only time we want to intercept motion events is if we are in the

* drag mode.

*/

  return mIsBeingDragged;

}

  • onTouchEvent 这里就是NestedScroll核心处理

    public boolean onTouchEvent(MotionEvent ev) {
        initVelocityTrackerIfNotExists();
    
        MotionEvent vtev = MotionEvent.obtain(ev);
    
        final int actionMasked = ev.getActionMasked();
    
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            //如果是down事件,NestedYOffset重置为0,表示是新一轮的内嵌滑动处理
            mNestedYOffset = 0;
        }
        //因为父ViewGroup能滑动,所以事件的位置也需要偏移滑动的距离
        vtev.offsetLocation(0, mNestedYOffset);
    
        switch (actionMasked) {
            case MotionEvent.ACTION_DOWN: {
                //没有View,后面的逻辑就不走了
                if (getChildCount() == 0) {
                    return false;
                }
                if ((mIsBeingDragged = !mScroller.isFinished())) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                }
    
                /*
                 * If being flinged and user touches, stop the fling. isFinished
                 * will be false if being flinged.
                 */
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }
    
                // Remember where the motion event started
                //down事件的时候,会获取点击点的位置,还有一次可能是从onInterceptTouchEvent里面获取,可以看相关源码
                mLastMotionY = (int) ev.getY();
                mActivePointerId = ev.getPointerId(0);
                //开始内嵌滑动
                startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH);
                break;
            }
            case MotionEvent.ACTION_MOVE:
                final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                if (activePointerIndex == -1) {
                    Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
                    break;
                }
    
                final int y = (int) ev.getY(activePointerIndex);
                int deltaY = mLastMotionY - y;
                //先父ViewGroup处理dispatchNestedPreScroll
                //注意,这里需要思考mScrollConsumed 是一个int[]数据
                if (dispatchNestedPreScroll(0, deltaY, mScrollConsumed, mScrollOffset,
                        ViewCompat.TYPE_TOUCH)) {
                    //这里需要减去消耗的距离
                    deltaY -= mScrollConsumed[1];
                    //事件偏移设置
                    vtev.offsetLocation(0, mScrollOffset[1]);
                    mNestedYOffset += mScrollOffset[1];
                }
                if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
                    final ViewParent parent = getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    mIsBeingDragged = true;
                    if (deltaY > 0) {
                        deltaY -= mTouchSlop;
                    } else {
                        deltaY += mTouchSlop;
                    }
                }
                if (mIsBeingDragged) {
                    // Scroll to follow the motion event
                    mLastMotionY = y - mScrollOffset[1];
    
                    final int oldY = getScrollY();
                    final int range = getScrollRange();
                    final int overscrollMode = getOverScrollMode();
                    boolean canOverscroll = overscrollMode == View.OVER_SCROLL_ALWAYS
                            || (overscrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0);
    
                    // Calling overScrollByCompat will call onOverScrolled, which
                    // calls onScrollChanged if applicable.
                    //自身滑动实现
                    if (overScrollByCompat(0, deltaY, 0, getScrollY(), 0, range, 0,
                            0, true) && !hasNestedScrollingParent(ViewCompat.TYPE_TOUCH)) {
                        // Break our velocity if we hit a scroll barrier.
                        mVelocityTracker.clear();
                    }
    
                    final int scrolledDeltaY = getScrollY() - oldY;
                    final int unconsumedY = deltaY - scrolledDeltaY;
                    //父ViewGroup处理dispatchNestedScroll,如果需要有滑动距离消耗的话
                    //注意dispatchNestedScroll的参数为啥不是int[],而是int 值
                    if (dispatchNestedScroll(0, scrolledDeltaY, 0, unconsumedY, mScrollOffset,
                            ViewCompat.TYPE_TOUCH)) {
                        mLastMotionY -= mScrollOffset[1];
                        vtev.offsetLocation(0, mScrollOffset[1]);
                        mNestedYOffset += mScrollOffset[1];
                    } else if (canOverscroll) {
                        ensureGlows();
                        final int pulledToY = oldY + deltaY;
                        if (pulledToY < 0) {
                            EdgeEffectCompat.onPull(mEdgeGlowTop, (float) deltaY / getHeight(),
                                    ev.getX(activePointerIndex) / getWidth());
                            if (!mEdgeGlowBottom.isFinished()) {
                                mEdgeGlowBottom.onRelease();
                            }
                        } else if (pulledToY > range) {
                            EdgeEffectCompat.onPull(mEdgeGlowBottom, (float) deltaY / getHeight(),
                                    1.f - ev.getX(activePointerIndex)
                                            / getWidth());
                            if (!mEdgeGlowTop.isFinished()) {
                                mEdgeGlowTop.onRelease();
                            }
                        }
                        if (mEdgeGlowTop != null
                                && (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) {
                            ViewCompat.postInvalidateOnAnimation(this);
                        }
                    }
                }
                break;
            case MotionEvent.ACTION_UP:
                final VelocityTracker velocityTracker = mVelocityTracker;
                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);
                if ((Math.abs(initialVelocity) > mMinimumVelocity)) {
                    flingWithNestedDispatch(-initialVelocity);
                } else if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
                        getScrollRange())) {
                    ViewCompat.postInvalidateOnAnimation(this);
                }
                mActivePointerId = INVALID_POINTER;
                endDrag();
                break;
            case MotionEvent.ACTION_CANCEL:
                if (mIsBeingDragged && getChildCount() > 0) {
                    if (mScroller.springBack(getScrollX(), getScrollY(), 0, 0, 0,
                            getScrollRange())) {
                        ViewCompat.postInvalidateOnAnimation(this);
                    }
                }
                mActivePointerId = INVALID_POINTER;
                endDrag();
                break;
            case MotionEvent.ACTION_POINTER_DOWN: {
                final int index = ev.getActionIndex();
                mLastMotionY = (int) ev.getY(index);
                mActivePointerId = ev.getPointerId(index);
                break;
            }
            case MotionEvent.ACTION_POINTER_UP:
                onSecondaryPointerUp(ev);
                mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
                break;
        }
    
        if (mVelocityTracker != null) {
            mVelocityTracker.addMovement(vtev);
        }
        vtev.recycle();
        return true;
    }
    

你可能感兴趣的:(Android NestedScroll dispatchNestedScroll方法参数为什么不是数组)