View源码之scrollBy()、scrollTo()解析

scrollBy()源码:

/**
 * Move the scrolled position of your view. This will cause a call to
 * {@link #onScrollChanged(int, int, int, int)} and the view will be
 * invalidated.
 * @param x the amount of pixels to scroll by horizontally
 * @param y the amount of pixels to scroll by vertically
 */
public void scrollBy(int x, int y) {
    scrollTo(mScrollX + x, mScrollY + y);
}

scrollTo()源码:

/**
 * Set the scrolled position of your view. This will cause a call to
 * {@link #onScrollChanged(int, int, int, int)} and the view will be
 * invalidated.
 * @param x the x position to scroll to
 * @param y the y position to scroll to
 */
public void scrollTo(int x, int y) {
    if (mScrollX != x || mScrollY != y) {
        int oldX = mScrollX;
        int oldY = mScrollY;
        mScrollX = x;
        mScrollY = y;
        invalidateParentCaches();
        onScrollChanged(mScrollX, mScrollY, oldX, oldY);
        if (!awakenScrollBars()) {
            postInvalidateOnAnimation();
        }
    }
}

好的,下面进行源码解析:

首先,简单介绍:

scrollBy---在现有的基础上继续移动视图的内容

scrollTo---将一个视图的内容移动到指定位置

然后,深入分析:

scrollBy方法,实际上还是调用了scrollTo()方法。将mScrollX加上scrollBy的第一个传

参x,将mScrollY加上scrollBy的第二个传参,然后调用scrollTo。

mScrollX和mScrollY是View中定义的两个变量,分别表示View的内容相对于View本身在

水平和垂直方向上的偏移量。

scrollTo方法,首先我们看这行代码

if(mScrollX != x || mScrollY != y)

我们可以看到,如果满足这个判断,scrollTo方法是没有做任何事情的。为什么要有

这个判断呢?原因是:如果这次移动的点的坐标和上次的一样,那么就没有必要进行移动了。

接着看,

int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;

这是用两个局部变量将之前的mScrollX和mScrollY保存下来,再将新的赋值给mScrollX和mScrollY,再来看,

invalidateParentCaches();

这是用于指示此视图的父级应清除其缓存,

再来看,

onScrollChanged(mScrollX, mScrollY, oldX, oldY);

调用了onScrollChanged方法,在方法里面回调了onScrollChange,源码:

mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);

最后执行了,

postInvalidateOnAnimation();

这个方法会通知View进行重绘,所以进入到draw()

我们知道draw()中有一步就是:绘制装饰,例如滚动条。

scrollbars就是由于scroll引起的,所以再来看这一步的具体实现:

public void onDrawForeground(Canvas canvas) {
    onDrawScrollIndicators(canvas);
    onDrawScrollBars(canvas);
    ...
}

onDrawScrollBars(canvas)分别绘制了水平和垂直方向的scrollBar,最终都会调用

invalidate方法。

该方法源码如下:

public void invalidate(Rect dirty) {
    final int scrollX = mScrollX;
    final int scrollY = mScrollY;
    invalidateInternal(dirty.left - scrollX, dirty.top - scrollY,
            dirty.right - scrollX, dirty.bottom - scrollY, true, false);
}

我们再跟进去看,

void invalidateInternal(int l, int t, int r, int b, 
        boolean invalidateCache, boolean fullInvalidate) {
    ...
    final Rect damage = ai.mTmpInvalRect;
    damage.set(l, t, r, b);
    p.invalidateChild(this, damage);
    ...
}

我们发现在这里重绘所有子控件,重绘时Rect的left、top减去了mScrollX,right、bottom减去了mScrollY。

因此我们也可以明白为什么当scrollX为正时,往左移动。

猜你喜欢

转载自blog.csdn.net/zdj_Develop/article/details/119444301
今日推荐