涨薪机密——新潮流新技术、新框架, 资源以后不定期更新,
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学科所有知识体系系统学习,无遗漏无瑕疵!
|