了解滚动阶段

滚动分为多个阶段。输入增量会通过一系列阶段进行分派,以确保每个阶段都有机会使用或响应移动。

在整个周期中,可用的输入增量和消耗的输入增量都会在每个步骤中传递。这为每个阶段提供了对滚动事件做出响应、使用或监听所需的完整上下文。

显示用户滚动事件的滚动阶段的滚动周期图
图 1. 一个滚动周期图,显示用户滚动事件的滚动阶段。

如图 1 所示,滚动过程严格遵循以下顺序:

  1. 滚动回弹:首先接收初始输入增量,这让滚动回弹有机会先做出反应(例如,通过放宽活跃的拉伸效果)。
  2. 嵌套滚动预滚动:让您有机会在滚动阶段之前对输入增量做出响应。在此阶段,系统可能会使用一些输入增量,也可能只是监控输入增量以触发界面更改,例如收起或展开应用栏。
  3. 转换输入增量:根据布局方向和方向调整原始输入增量的符号,以确保自然的滚动行为。如需了解详情,请参阅转换输入增量部分。
  4. 滚动:此阶段会接收经过调整以匹配滚动容器配置的可用、未使用的输入增量。它通常会使用此增量来更新自己的滚动偏移量。
  5. 还原为原始输入增量:将滚动阶段的可用增量和已消耗增量还原为原始输入增量符号。
  6. 嵌套滚动后滚动:此阶段在主滚动阶段完成后做出响应,接收新更新的可用和已用增量。它可以消耗任何剩余的可用输入,也可以使用刚刚消耗的内容的上下文。
  7. 滚动回弹:最后一个阶段会查看最终可用和已使用的增量。到达此阶段的任何剩余可用输入通常用于驱动边缘效果(例如拉伸或发光),以指示用户已到达可滚动区域的边界。

转换输入增量

指针输入增量需要跨滚动阶段进行符号调整,以匹配预期协定。在增量到达滚动阶段之前,滚动修饰符会根据方向、布局方向和 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 为负数) 不适用 不适用