滚动分为多个阶段。输入增量会通过一系列阶段进行分派,以确保每个阶段都有机会使用或响应移动。
在整个周期中,可用的输入增量和消耗的输入增量都会在每个步骤中传递。这为每个阶段提供了对滚动事件做出响应、使用或监听所需的完整上下文。
如图 1 所示,滚动过程严格遵循以下顺序:
- 滚动回弹:首先接收初始输入增量,这让滚动回弹有机会先做出反应(例如,通过放宽活跃的拉伸效果)。
- 嵌套滚动预滚动:让您有机会在滚动阶段之前对输入增量做出响应。在此阶段,系统可能会使用一些输入增量,也可能只是监控输入增量以触发界面更改,例如收起或展开应用栏。
- 转换输入增量:根据布局方向和方向调整原始输入增量的符号,以确保自然的滚动行为。如需了解详情,请参阅转换输入增量部分。
- 滚动:此阶段会接收经过调整以匹配滚动容器配置的可用、未使用的输入增量。它通常会使用此增量来更新自己的滚动偏移量。
- 还原为原始输入增量:将滚动阶段的可用增量和已消耗增量还原为原始输入增量符号。
- 嵌套滚动后滚动:此阶段在主滚动阶段完成后做出响应,接收新更新的可用和已用增量。它可以消耗任何剩余的可用输入,也可以使用刚刚消耗的内容的上下文。
- 滚动回弹:最后一个阶段会查看最终可用和已使用的增量。到达此阶段的任何剩余可用输入通常用于驱动边缘效果(例如拉伸或发光),以指示用户已到达可滚动区域的边界。
转换输入增量
指针输入增量需要跨滚动阶段进行符号调整,以匹配预期协定。在增量到达滚动阶段之前,滚动修饰符会根据方向、布局方向和 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 为正数) | 不适用 | 不适用 |
| 指针向右移动 | 正面 | 正面 | 正面 | 负数(对于 RTL 为正数) | 正数(对于 RTL 为负数) | 不适用 | 不适用 |