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() メソッドを呼び出します。scrollBy の最初のパスに mScrollX を追加します。
パラメータ x、mScrollY を scrollBy の 2 番目のパラメータに追加してから、scrollTo を呼び出します。
mScrollX と mScrollY は、View で定義された 2 つの変数であり、View 自体に対する View のコンテンツをそれぞれ表します。
水平および垂直方向のオフセット。
scrollTo メソッドでは、まずこのコード行を見てください
if(mScrollX != x || mScrollY != y)
この判定が満たされた場合、scrollTo メソッドは何もしないことがわかります。なぜあるべきか
この判決はどうなる?その理由は、今回の移動点の座標が前回と同じであれば、移動する必要がないからです。
次に見て、
int oldX = mScrollX;
int oldY = mScrollY;
mScrollX = x;
mScrollY = y;
これは、2 つのローカル変数を使用して、以前の mScrollX と mScrollY を保存してから、mScrollX と mScrollY に新しい値を割り当てるというものです。
invalidateParentCaches();
これは、このビューの親がそのキャッシュをクリアする必要があることを示すために使用されます。
もう一度見て、
onScrollChanged(mScrollX, mScrollY, oldX, oldY);
onScrollChanged メソッドが呼び出され、メソッドのソース コードで onScrollChange が呼び出されます。
mListenerInfo.mOnScrollChangeListener.onScrollChange(this, l, t, oldl, oldt);
最終的に実行され、
postInvalidateOnAnimation();
このメソッドは View に再描画を通知するので、 draw() を入力します
draw() の 1 つのステップは、スクロール バーなどの装飾を描画することです。
スクロールバーはスクロールによって発生するため、このステップの具体的な実装を見てみましょう。
public void onDrawForeground(Canvas canvas) {
onDrawScrollIndicators(canvas);
onDrawScrollBars(canvas);
...
}
onDrawScrollBars(canvas) は、それぞれ水平スクロールバーと垂直スクロールバーを描画し、最終的に呼び出されます
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 の左と上から mScrollX を引いたものと、右と下から mScrollY を引いたものです。
したがって、scrollX が正の場合に左に移動する理由も理解できます。