A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

涨薪机密——潮流新技术、新框架资源以后不定期更新,
  
4.overSceollBy 方法被谁调用,传递了什么值
既然需要研究系统代码执行,那就只能是使用 Debug 调试来查看运行过程了,首先要确定到哪里打断点。
在文章开始说过,overScrollBy 是一个在 View 里定义的方法 ,但是 View 并没有处理具体的调用逻辑。真正调用 overSrollBy 方法的是那些可以滚动的控件,比如 AbsListView、HorizontalScrollView、ScrollView。
经过查看,在 ListView 里没有调用 overScrollBy 方法,而在 AbsListView 里由 4 处调用,全部打上断点,运行等待执行。

4.1当手指下拉时执行的代码
[Java] 纯文本查看 复制代码
private void scrollIfNeeded(int x, int y, MotionEvent vtev) {
  int rawDeltaY = y - mMotionY;
  // .......

  final int deltaY = rawDeltaY;
  int incrementalDeltaY =
    mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;
  // .....

  int overscroll = -incrementalDeltaY -
    (motionViewRealTop - motionViewPrevTop);
  // ....

  final boolean atOverscrollEdge = overScrollBy(0, overscroll,
                                                0, mScrollY, 0, 0, 0, mOverscrollDistance, true);

  //....


4.2当手指下拉时执行的 Debug 截图

4.3当手指下拉时执行的数据分析
可以看到最终传递的 overscroll 变量,在一般情况下,就是等于 incrementalDeltaY 的值,而 incrementalDeltaY 最终数据是来自下面的代码

[Java] 纯文本查看 复制代码
int incrementalDeltaY =
                mLastY != Integer.MIN_VALUE ? y - mLastY + scrollConsumedCorrection : deltaY;

先看简单的变量 deltaY,它是来自 rawDeltaY,在 scrollIfNeeded 方法第一句可以看到,

[Java] 纯文本查看 复制代码
int rawDeltaY = y - mMotionY;

这里的 scrollIfNeeded 方法最终是在 onTouchEvent 方法的 ACTION_MOVE 事件被调用,y 就是事件发生时的手指位置。而 mMotionY 的值根据查看文档说明,

[Java] 纯文本查看 复制代码
/**
 * The Y value associated with the the down motion event
 * 在down事件时的手指Y位置
 */
int mMotionY;
也就是手指按下时的位置。那么 rawDeltaY 也就是 "当前手指位置 - 手指按下的位置"
但是这只是 mLastY !=Integer.MIN_VALUE 不成立时的值,这个条件什么时候会成立呢,经过查找, mLastY 是在 onTouchEvent 的 ACTION_DOWN 事件时被赋值为 Integer.MIN_VALUE。
也就是只有在手指按下的时候, incrementalDeltaY 使用 rawDetalY 的值,其他时候都是使用 y - mLastY +scrollConsumedCorrection,经过调试,scrollConsumedCorrection 一般都是保持在 0 ,而 mLastY 记录的就是上一次手指的位置,那么的表达式就是"当前手指位置 - 手指按下的位置",计算出来的 incrementalDeltaY 在赋值给 overscroll 变量前,又被转换为了 -incrementalDeltaY ,那么表达式最终就是 "手指按下的位置 - 当前手指位置"
转换一下语义的话就是我们之前猜测的"旧的Y位置 - 新的Y位置"符合预期。
4.4当惯性滑动到顶部时的代码
[Java] 纯文本查看 复制代码
private class FlingRunnable implements Runnable {
    // .....

    @Override
    public void run() {
        switch (mTouchMode) {
        //....

        case TOUCH_MODE_OVERFLING: {
            final OverScroller scroller = mScroller;
            if (scroller.computeScrollOffset()) {
                final int scrollY = mScrollY;
                final int currY = scroller.getCurrY();
                final int deltaY = currY - scrollY;
                if (overScrollBy(0, deltaY, 0, scrollY, 0, 0,
                        0, mOverflingDistance, false)) {
                    // ....
        }
        }
    }
}
4.5 当惯性滑动到顶部时的 Debug 截图


4.6当惯性滑动到顶部时的数据分析
可以看到,由手指滑动和惯性滑动确实是执行了不同的代码块。
这里的代码是在屏幕自动滑动时执行,而 deltaY 是来自:

[Java] 纯文本查看 复制代码

final int deltaY = currY - scrollY;

其中,currY 是根据波纹动画时间计算的下一次移动位置;scrollY 是来自 View 类,在记录了上一次滚动后的位置。
由此证实了之前猜测的算法,当惯性滑动时,deltaY 的值是 新的Y位置 - 旧的Y位置”
打印出下面的 Log 也可以理解了,
[Java] 纯文本查看 复制代码
I/System.out: deltaY=1;     scrollY=-8;   isTouchEvent=false
I/System.out: deltaY=3;     scrollY=-7;   isTouchEvent=false
I/System.out: deltaY=2;     scrollY=-4;   isTouchEvent=false
这里是先有了下一步的移动位置,然后才计算出来 deltaY 只是新的位置还没有真的使用到 View 上,所以返回的是上一次的位置。

5.总结
•            deltaY 的值确实是根据不同的操作,使用了不同的算法。当手势拖拽的时候是使用 "旧的Y位置 - 新的Y位置" ,当惯性滑动的时候是使用 "新的Y位置 - 旧的Y位置"
•             scrollY 的值是上一次移动的值,deltaY 是''列表移动之后"根据新位置计算出来的偏移量。之所以打印时先出现 deltaY,后出现移动的新位置,是因为新位置还没有应用到列表上。

年度最佳精华推荐奖:

跟随Android学科所有知识体系系统学习,无遗漏无瑕疵!   


1 个回复

倒序浏览
厉害厉害
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马