当组件内容超过当前显示视口(ViewPort)时,如果没有特殊处理,Flutter 则会提示 Overflow 错误。为此,Flutter 提供了多种可滚动组件(Scrollable Widget)用于显示列表和长布局。

Scrollable

可滚动组件都直接或间接包含一个 Scrollable 组件

  1. Scrollable({
  2. ...
  3. this.axisDirection = AxisDirection.down,
  4. this.controller,
  5. this.physics,
  6. @required this.viewportBuilder,
  7. })

参数

  • axisDirection:滚动方向。
  • physics:此属性接受一个 ScrollPhysics 类型的对象,它决定可滚动组件如何响应用户操作,比如用户滑动完抬起手指后,继续执行动画;或者滑动到边界时,如何显示。默认情况下,Flutter 会根据具体平台分别使用不同的 ScrollPhysics 对象,应用不同的显示效果,如当滑动到边界时,继续拖动的话,在 iOS 上会出现弹性效果,而在 Android 上会出现微光效果。
    • Flutter SDK 中包含了两个 ScrollPhysics 的子类,他们可以直接使用:
      • ClampingScrollPhysics Android 下微光效果。
      • BouncingScrollPhysics iOS 下弹性效果。
  • controller:此属性接受一个 ScrollController 对象。ScrollController 的主要作用是控制滚动位置和监听滚动事件。

SingleChildScrollView

SingleChildScrollView 就是普通的滚动视图, 允许存在单个子节点

  1. SingleChildScrollView({
  2. this.scrollDirection = Axis.vertical,
  3. this.reverse = false,
  4. this.padding,
  5. bool primary,
  6. this.physics,
  7. this.controller,
  8. this.child,
  9. })

参数

  • scrollDirection 滚动方向,默认是垂直方向
    • Axis.vertical 垂直方向
    • Axis.horizontal 水平方向
  • reverse 是否按照阅读方向相反的方向滑动
  • primary 指是否使用 widget 树中默认的 PrimaryScrollController;当滑动方向为垂直方向(scrollDirection 值为 Axis.vertical)并且没有指定 controller 时,primary 默认为 true.

示例: 垂直方向滚动

  1. Scrollbar(
  2. child: SingleChildScrollView(
  3. padding: EdgeInsets.all(16.0),
  4. child: Center(
  5. child: Column(
  6. children: "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").map((c) =>
  7. Text(c, textScaleFactor: 2.0,)).toList(),
  8. ),
  9. ),
  10. ),
  11. )

效果:
007.gif

示例: 水平方向滚动

  1. crollbar(
  2. child: SingleChildScrollView(
  3. scrollDirection: Axis.horizontal,
  4. padding: EdgeInsets.all(16.0),
  5. child: Center(
  6. child: Row(
  7. children: "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("").map((c) =>
  8. Text(c, textScaleFactor: 2.0,)).toList(),
  9. ),
  10. ),
  11. ),
  12. ),

效果:
008.gif

Scrollbar

Scrollbar 是一个 Material 风格的滚动指示器(滚动条),如果要给可滚动组件添加滚动条,只需将 Scrollbar 作为可滚动组件的任意一个父级组件即可

Scrollbar 和 CupertinoScrollbar 都是通过 ScrollController 来监听滚动事件来确定滚动条位置的。

相关概念

ViewPort 视口

在很多布局系统中都有 ViewPort 的概念,在 Flutter 中,术语 ViewPort(视口),如无特别说明,则是指一个 Widget 的实际显示区域。例如,一个 ListView 的显示区域高度是 800 像素,虽然其列表项总高度可能远远超过 800 像素,但是其 ViewPort 仍然是 800 像素。

基于 Sliver 的延迟构建

通常可滚动组件的子组件可能会非常多、占用的总高度也会非常大;如果要一次性将子组件全部构建出将会非常昂贵!为此,Flutter 中提出一个 Sliver(中文为“薄片”的意思)概念,如果一个可滚动组件支持 Sliver 模型,那么该滚动可以将子组件分成好多个“薄片”(Sliver),只有当 Sliver 出现在视口中时才会去构建它,这种模型也称为“基于 Sliver 的延迟构建模型”。可滚动组件中有很多都支持基于 Sliver 的延迟构建模型,如 ListView、GridView,但是也有不支持该模型的,如 SingleChildScrollView。

主轴和纵轴

在可滚动组件的坐标描述中,通常将滚动方向称为主轴,非滚动方向称为纵轴。由于可滚动组件的默认方向一般都是沿垂直方向,所以默认情况下主轴就是指垂直方向,水平方向同理。

其他

  • CupertinoScrollbar 是 iOS 风格的滚动条,如果你使用的是 Scrollbar,那么在 iOS 平台它会自动切换为 CupertinoScrollbar。