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
时,即滑动发现为水平,如果阅读方向是从左到右(取决于语言环境,阿拉伯语就是从右到左)。reverse
为true
时,那么滑动方向就是从右往左。
需要注意的是,通常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(),
),
),
);
}
}
示例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),
),
);
}),
),
),
);
}
}
示例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,
),
),
);
}),
),
);
}
}