了解滚动阶段

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

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

一个滚动周期图,显示用户滚动事件的滚动阶段
图 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 为负) 不适用 不适用