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

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

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

ユーザー スクロール イベントのスクロール フェーズを示すスクロール サイクル図
図 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(縦向き、反転)
ポインタがに移動する 陰性 陰性 陰性 なし なし ポジティブ 陰性
ポインタが DOWN に移動 ポジティブ ポジティブ ポジティブ なし なし 陰性 ポジティブ
ポインタがに移動する 陰性 陰性 陰性 正(RTL の場合は負) 否定的(RTL の場合は肯定的) なし なし
ポインタがに移動する ポジティブ ポジティブ ポジティブ 否定的(RTL の場合は肯定的) 正(RTL の場合は負) なし なし