捲動分為多個階段。輸入差異會透過一系列階段分派,確保每個階段都有機會消耗或回應動作。
在這個週期中,可用的輸入差異和消耗的輸入差異都會在每個步驟中傳遞。這樣一來,每個階段都能取得完整背景資訊,以便回應、使用或監聽捲動事件。

如圖 1 所示,捲動程序會按照以下順序進行:
- 過度捲動:先接收初始輸入差異,讓過度捲動有機會先做出反應 (例如放寬主動延展效果)。
- 巢狀捲動預先捲動:在「捲動」階段之前,有機會對輸入差異做出反應。在這個階段,系統可能會耗用部分輸入差異,或只是監控輸入差異,以觸發 UI 變更,例如收合或展開應用程式列。
- 轉換輸入差異:根據版面配置方向和方向調整原始輸入差異的正負號,確保捲動行為自然。詳情請參閱「轉換輸入差異」一節。
- 捲動:這個階段會接收可用的未消耗輸入差異,並根據捲動容器設定進行調整。通常會使用這個差異值更新自己的捲動偏移。
- 還原為原始輸入差異:將捲動階段的可用和已消耗差異,還原為原始輸入差異符號。
- 巢狀捲動後捲動:這個階段會在主要捲動階段完成後做出反應,接收新更新的可用和已消耗差異。它可以消耗任何剩餘的可用輸入內容,或使用剛消耗內容的脈絡。
- 過度捲動:最後一個階段會查看最終可用和已消耗的差異。任何剩餘的可用輸入內容,通常會用於驅動邊緣效果,例如拉伸或發光,表示使用者已達到可捲動區域的邊界。
轉換輸入差異
指標輸入差異需要調整捲動階段的正負號,才能符合預期合約。在差異值達到「捲動」階段之前,捲動修飾符會根據方向、版面配置方向和 RTL 情境調整輸入差異值。這是因為原始輸入會追蹤指標在螢幕上的實體像素移動 (例如向下移動會增加螢幕的 Y 座標,產生正差異)。不過,如要達到「自然捲動」效果,讓內容隨著手指移動,向下拖曳代表可視區域必須向上移動,這對應到負捲動偏移。
滑鼠滾輪或觸控板等其他輸入來源的輸入差異,在捲動階段不會轉換。
範例:使用 Modifier.horizontalScroll() 將指標向右移動

如要瞭解如何使用及轉換差異,請參閱圖 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 為正值) | 正值 (由右至左為負值) | 不適用 | 不適用 |