Flutter 可滚动组件 之 SingleChildScrollView (十五)

1. SingleChildScrollView

SingleChildScrollView 源码定义如下:

  const SingleChildScrollView({
    Key? key,
    this.scrollDirection = Axis.vertical,
    this.reverse = false,
    this.padding,
    bool? primary,
    this.physics,
    this.controller,
    this.child,
    this.dragStartBehavior = DragStartBehavior.start,
    this.clipBehavior = Clip.hardEdge,
    this.restorationId,
    this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
  })
  • primary:它表示是否使用 widget 树中默认的PrimaryScrollController(MaterialApp 组件树中已经默认包含一个 PrimaryScrollController 了);当滑动方向为垂直方向(scrollDirection值为Axis.vertical)并且没有指定controller时,primary默认为true。不能在显示指定controller后,再设置primary为true。

  • scrollDirection 滚动方向。

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

    • ClampingScrollPhysics:列表滑动到边界时将不能继续滑动,通常在Android 中 配合 GlowingOverscrollIndicator(实现微光效果的组件) 使用。
    • BouncingScrollPhysics:iOS 下弹性效果。
  • controller:此属性接受一个ScrollController对象。ScrollController的主要作用是控制滚动位置和监听滚动事件。默认情况下,Widget树中会有一个默认的PrimaryScrollController,如果子树中的可滚动组件没有显式的指定controller,并且primary属性值为true时(默认就为true),可滚动组件会使用这个默认的PrimaryScrollController。这种机制带来的好处是父组件可以控制子树中可滚动组件的滚动行为,例如,Scaffold正是使用这种机制在iOS中实现了点击导航栏回到顶部的功能。我们将在本章后面“滚动控制”一节详细介绍ScrollController

  • reverse表示是否按照阅读方向相反的方向滑动,如:scrollDirection值为Axis.horizontal时,即滑动发现为水平,如果阅读方向是从左到右(取决于语言环境,阿拉伯语就是从右到左)。reversetrue时,那么滑动方向就是从右往左。

需要注意的是,通常SingleChildScrollView只应在期望的内容不会超过屏幕太多时使用,这是因为SingleChildScrollView不支持基于 Sliver 的延迟加载模型,所以如果预计视口可能包含超出屏幕尺寸太多的内容时,那么使用SingleChildScrollView将会非常昂贵(性能差),此时应该使用一些支持Sliver延迟加载的可滚动组件,如ListView

2. 示例

示例1
下面是一个将大写字母 A-Z 沿垂直方向显示的例子,由于垂直方向空间会超过屏幕视口高度,所以我们使用SingleChildScrollView:

class SingleChildScrollViewDemo1 extends StatelessWidget {
  SingleChildScrollViewDemo1({
    Key? key,
  }) : super(key: key);

  final String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      controller: null,
      child: Center(
        child: Column(
          //动态创建一个List<Widget>
          children: str.split("").map((e) {
            return Text(e,
                textScaleFactor: 2.0, style: TextStyle(color: Colors.orange));
          }).toList(),
        ),
      ),
    );
  }
}

image.png

示例2

class SingleChildScrollViewDemo2 extends StatelessWidget {
  const SingleChildScrollViewDemo2({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      padding: EdgeInsets.symmetric(vertical: 10),
      child: Center(
        child: Column(
          // generate 快速生成值列表
          children: List.generate(100, (index) {
            return Container(
              padding: EdgeInsets.all(8),
              child: Text(
                "联系人 ${index + 1}",
                style: TextStyle(fontSize: 20, color: Colors.orange),
              ),
            );
          }),
        ),
      ),
    );
  }
}
image.png

示例3 - 横向滚动

class SingleChildScrollViewDemo3 extends StatelessWidget {
  const SingleChildScrollViewDemo3({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      padding: EdgeInsets.symmetric(vertical: 20),
      child: Row(
        children: List.generate(100, (index) {
          return Container(
            height: 200,
            width: 200,
            color: Color.fromARGB(Random().nextInt(256), Random().nextInt(256),
                Random().nextInt(256), Random().nextInt(256)),
            child: Center(
              child: Text(
                "$index",
                textScaleFactor: 2.0,
              ),
            ),
          );
        }),
      ),
    );
  }
}
image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容