スクロール フェーズについて

スクロールは複数のフェーズに分かれています。入力デルタは、各フェーズが移動を消費または反応する機会を確保するために、一連のフェーズを通じてディスパッチされます。

このサイクル全体を通じて、利用可能な入力デルタと消費された入力デルタの両方が、すべてのステップで渡されます。これにより、各フェーズでスクロール イベントに反応、消費、リッスンするために必要な完全なコンテキストが提供されます。

ユーザー スクロール イベントのスクロール フェーズを示すスクロール サイクル図
図 1. ユーザー スクロール イベントのスクロール フェーズを示すスクロール サイクル図。

図 1 に示すように、スクロール プロセスは次の順序で行われます。

  1. オーバースクロール: 最初に初期入力デルタを受け取ります。これにより、オーバースクロールが最初に反応する機会が得られます(たとえば、アクティブなストレッチ効果を緩和するなど)。
  2. ネストされたスクロールの事前スクロール: スクロール フェーズの前に、入力デルタに対応する機会を提供します。このフェーズでは、入力デルタの一部が消費されるか、UI の変更(アプリバーの折りたたみや展開など)をトリガーするためにモニタリングされるだけです。
  3. 入力デルタを変換する: レイアウトの向きと方向に基づいて、未加工の入力デルタの符号を調整し、自然なスクロール動作を実現します。詳細については、入力デルタを変換するセクションをご覧ください。
  4. スクロール: このフェーズでは、スクロール コンテナの構成に合わせて調整された、使用可能な未消費の入力デルタを受け取ります。通常、この差分を使用して独自のスクロール オフセットを更新します。
  5. 未加工の入力デルタに戻す: スクロール フェーズで使用可能なデルタと消費されたデルタを、元の未加工の入力デルタ記号に戻します。
  6. ネストされたスクロールのスクロール後: このフェーズは、メインのスクロール フェーズが完了した後に反応し、新しく更新された利用可能な差分と消費された差分を受け取ります。残りの使用可能な入力を消費することも、消費されたばかりのコンテキストを使用することもできます。
  7. オーバースクロール: この最後のフェーズでは、最終的に利用可能なデルタと消費されたデルタを確認します。この段階に到達した残りの利用可能な入力は、通常、ストレッチやグローなどのエッジ効果を駆動するために使用され、ユーザーがスクロール可能領域の境界に到達したことを示します。

入力デルタを変換する

ポインタ入力デルタでは、想定されるコントラクトに一致するように、スクロール フェーズ全体で符号の調整が必要です。デルタが Scroll フェーズに到達する前に、スクロール修飾子が、向き、レイアウト方向、RTL コンテキストに基づいて入力デルタを調整します。これは、未加工入力が画面上のポインタの物理的なピクセル移動を追跡するためです(たとえば、下に移動すると画面の Y 座標が増加し、正のデルタが生成されます)。ただし、コンテンツが指の動きに合わせて移動する「ナチュラル スクロール」を実現するには、下にドラッグするとビューポートがコンテンツの上方向に移動する必要があります。これは、負のスクロール オフセットに対応します。

マウスホイールやタッチパッドなど、他の入力ソースからの入力デルタは、スクロール フェーズ全体で変換されません。

例: Modifier.horizontalScroll() を使用してポインタを右に移動する

ポインタが右に移動するジェスチャーを示すグラフ
図 2. ポインタが右に移動するジェスチャーをマッピングするグラフ。

デルタがどのように消費され、変換されるかを理解するには、ポインタが右に移動するジェスチャーをマッピングした図 2 をご覧ください。

  • スクロール前: ジェスチャーは、100 の正の未加工入力デルタで始まります。
    • オーバースクロールはこれを監視し、10 を消費して 90 を残します。
    • ネストされたスクロールの事前スクロールにより、親コンポーネントが反応して 30 を消費する機会が与えられます。残りの未加工のデルタは 60 です。
  • 変換 A: スクロール フェーズに入る前に、horizontalScroll は残りの正の未加工デルタ(60)を負のデルタ(-60)に反転します。これにより、ビューポートが左にシフトし、コンテンツがユーザーの指に合わせて右に移動しているように見えます。
  • スクロール: ターゲットのスクロール可能なコンポーネントは、この変換されたデルタの一部を消費して、スクロール オフセットを更新します。この例では、-30 が消費され、-30 が消費されずに残ります。
  • 変換 B: 未消費のスクロール デルタ (-30)は、ネストされたスクロールとオーバースクロールのコントラクトに合わせて、正の未加工デルタ (30)に変換されます。
  • スクロール後: 残りの未加工のデルタがパイプラインに返されます。
    • ネストされたスクロールのポストスクロールが 10 を消費し、20 が残ります。
    • オーバースクロール効果は、最後の 20 を使用して、ストレッチやグローなどの視覚的なエッジ効果を駆動し、入力デルタを 0 に完全に解決します。

ポインタ入力デルタ変換リファレンス

次の表に、ポインタ入力のさまざまなフェーズと方向で入力デルタがどのように符号化されるかを示します。

未加工の入力差分 オーバースクロール効果 ネストされたスクロール scrollableArea(横向き) scrollableArea(横向き、反転) scrollableArea(縦向き) scrollableArea(縦向き、反転)
ポインタが上に移動する 陰性 陰性 陰性 なし なし ポジティブ 陰性
ポインタが下に移動する ポジティブ ポジティブ ポジティブ なし なし 陰性 ポジティブ
ポインタが左に移動する 陰性 陰性 陰性 正(RTL の場合は負) 負(RTL の場合は正) なし なし
ポインタが右に移動する ポジティブ ポジティブ ポジティブ 負(RTL の場合は正) 正(RTL の場合は負) なし なし