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;
    }
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容