scrollBy() source code:
/**
* 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() source code:
/**
* 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();
}
}
}
Ok, let’s analyze the source code below:
First, a brief introduction:
scrollBy --- continue to move the content of the view on the existing basis
scrollTo---Move the content of a view to the specified position
Then, drill down to:
The scrollBy method actually calls the scrollTo() method. Add mScrollX to the first pass of scrollBy
Parameter x, add mScrollY to the second parameter of scrollBy, and then call scrollTo.
mScrollX and mScrollY are two variables defined in View, which respectively represent the content of View relative to View itself.
Offsets in the horizontal and vertical directions.
scrollTo method, first we look at this line of code
if(mScrollX != x || mScrollY != y)
We can see that if this judgment is met, the scrollTo method does nothing. why should there be
What about this judgment? The reason is: if the coordinates of the moving point this time are the same as last time, then there is no need to move.
look next,
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
This is to use two local variables to save the previous mScrollX and mScrollY, and then assign new values to mScrollX and mScrollY. Let’s look again,
invalidateParentCaches();
This is used to indicate that this view's parent should clear its cache,
Look again,
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
The onScrollChanged method is called, and onScrollChange is called back in the method, source code:
mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
Finally executed,
postInvalidateOnAnimation();
This method will notify View to redraw, so enter draw()
We know that one step in draw() is: draw decorations, such as scroll bars.
Scrollbars is caused by scroll, so let's look at the specific implementation of this step:
public void onDrawForeground(Canvas canvas) {
onDrawScrollIndicators(canvas);
onDrawScrollBars(canvas);
...
}
onDrawScrollBars(canvas) draws the horizontal and vertical scrollBar respectively, and will eventually be called
invalidate method.
The source code of this method is as follows:
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);
}
Let's follow up and see,
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);
...
}
We found that all child controls are redrawn here. When redrawing, the left and top of the Rect minus mScrollX, and the right and bottom minus mScrollY.
So we can also understand why when scrollX is positive, move to the left.