赞
踩
目录
Flutter中有两种布局模型:Render的盒模型布局和Sliver按需加载列表布局。
可滚动的组件的子组件一般会很多,如果一次性全部加载会影响性能。为此Flutter提供了Sliver(片段),Sliver可以包含多个子组件。Sliver作用:按需加载子组件并确定每一个子组件的布局。
Flutter中可滚动主要由三部分组成:
Scrollable,用于处理滑动手势,确定滑动偏移,滑动时构建Viewport;
Viewport,显示的视窗,即列表的可视区域;
Sliver,视窗里显示的元素;
布局过程:
Scrollable,监听到用户滑动后,根据滑动偏移构建Viewport;
Viewport将当前视口信息和配置信息通过SliverConstraints传递给Sliver;
Sliver中对子组件按需进行构建和布局;
用来处理滑动,确定偏移量,在滑动时构建Viewport。
- Scrollable({
- ...
- this.axisDirection = AxisDirection.down,
- this.controller,
- this.physics,
- required this.viewportBuilder, //后面介绍
- })
axisDirection,滚动方向;
controller,此属性接受一个ScrollController
对象。ScrollController
的主要作用是控制滚动位置和监听滚动事件;
physics,此属性接受一个ScrollPhysics
类型的对象,决定可滚动组件如何响应用户操作;
viewportBuilder,构建 Viewport 的回调;
用于渲染当前视口中需要显示 Sliver。
- Viewport({
- Key? key,
- this.axisDirection = AxisDirection.down,
- this.crossAxisDirection,
- this.anchor = 0.0,
- required ViewportOffset offset, // 用户的滚动偏移
- // 类型为Key,表示从什么地方开始绘制,默认是第一个元素
- this.center,
- this.cacheExtent, // 预渲染区域
- //该参数用于配合解释cacheExtent的含义,也可以为主轴长度的乘数
- this.cacheExtentStyle = CacheExtentStyle.pixel,
- this.clipBehavior = Clip.hardEdge,
- List<Widget> slivers = const <Widget>[], // 需要显示的 Sliver 列表
- })
作用是对子组件进行构建和布局
Scrollbar
是一个Material风格的滚动指示器(滚动条),如果要给可滚动组件添加滚动条,只需将Scrollbar
作为可滚动组件的任意一个父级组件即可。
SingleChildScrollView
类似于Android中的ScrollView
,它只能接收一个子组件:
- SingleChildScrollView({
- this.scrollDirection = Axis.vertical, //滚动方向,默认是垂直方向
- this.reverse = false,
- this.padding,
- bool primary,
- this.physics,
- this.controller,
- this.child,
- })
primary,表示是否使用 widget 树中默认的PrimaryScrollController;
当滑动方向为垂直方向(scrollDirection
值为Axis.vertical
)并且没有指定controller
时,primary
默认为true。
SingleChildScrollView
不支持基于 Sliver 的延迟加载模型,所以如果超出屏幕的内容太多性能会很差,此时应该使用支持Sliver延迟加载的可滚动组件如ListView。
- String str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- return Scrollbar(
- child: SingleChildScrollView(
- child: Center(
- child: Column(
- children: str
- .split('')
- .map(
- (item) => Text(
- item,
- textScaleFactor: 2,
- ),
- )
- .toList(),
- ),
- ),
- ),
- );
效果:
可以沿一个方向线性排布所有子组件,也支持列表项懒加载。
- ListView({
- ...
- //可滚动widget公共参数
- Axis scrollDirection = Axis.vertical,
- bool reverse = false,
- ScrollController? controller,
- bool? primary,
- ScrollPhysics? physics,
- EdgeInsetsGeometry? padding,
-
- //ListView各个构造函数的共同参数
- double? itemExtent,
- Widget? prototypeItem, //列表项原型,后面解释
- bool shrinkWrap = false,
- bool addAutomaticKeepAlives = true,
- bool addRepaintBoundaries = true,
- double? cacheExtent, // 预渲染区域长度
-
- //子widget列表
- List<Widget> children = const <Widget>[],
- })
itemExtent,如果不为null
则会强制children
的“长度”为itemExtent
的值,此处的长度指的是滚动方向上组件的长度。指定itemExtent让子组件自身决定自身长度会有更好的性能,因为指定后滚动系统可以提前知道列表长度;
prototypeItem,如果知道列表项长度相同但不知道具体多少,可以指定一个列表项,指定后滚动组件会在layout时计算一次主轴方向的长度,会有更好的性能;
shrinkWrap,表示是否根据子组件的总长度来设置ListView的长度,默认为false;
children,接受一个List<Widget>,该方式只适合子组件数量较少时,反之应该使用ListView.builder来动态构建;
- return Scrollbar(
- child: ListView(
- shrinkWrap: true,
- padding: const EdgeInsets.all(20),
- children: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
- .split('')
- .map(
- (item) => Text(
- item,
- textScaleFactor: 2,
- ),
- )
- .toList(),
- ),
- );
适合列表项比较多或者列表项不确定的情况。
- ListView.builder({
- // ListView公共参数已省略
- ...
- required IndexedWidgetBuilder itemBuilder,
- int itemCount,
- ...
- })
itemBuilder,列表项的构建器,类型为IndexedWidgetBuilder
,返回值为一个widget;当列表滚动到具体的index
位置时,会调用该构建器构建列表项;
itemCount,列表项的数量,如果为null
,则为无限列表;
可以在生成的列表项之间添加一个分割组件,separatorBuilder
参数,该参数是一个分割组件生成器。
- child: ListView.separated(
- itemCount: 100,
- itemBuilder: (BuildContext context, int index) {
- return ListTile(title: Text('$index'));
- },
- separatorBuilder: (BuildContext context, int index) {
- return const Divider(
- color: Colors.black26,
- );
- },
- ),
效果:
4. 滚动监听和控制
4.1ScrollController
- ScrollController({
- double initialScrollOffset = 0.0, //初始滚动位置
- this.keepScrollOffset = true,//是否保存滚动位置
- ...
- })
滚动监听
ScrollController
间接继承自Listenable
,我们可以根据ScrollController
来监听滚动事件:
controller.addListener(()=>print(controller.offset))
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。