前言
我们在使用ListView嵌套ListView时,我们往往会用shrinkWrap解决Vertical viewport was given unbounded height问题,但是这样也导致了隐藏的性能问题,因为这会使得shrinkWrap为true的ListView内的所有item在初始化时就全部渲染了。如果该组件显示的item有成千上万个会造成明显的性能问题。接下来我通过一个例子探讨一下用CustomScrollView和SliverList组件多方向的滑动布局。
正文部分
我们按照下图中的布局:两个横向的ListView,一个竖向的ListView。通过CustomScrollView来实现它们。
代码部分
Step.1
先打好外部框架,因为大体是垂直布局所以加上Axis.vertical,slivers内添加两个SliverList
,注意:他们的delegate属性实现的函数不同
。
SliverChildListDelegate:
该函数接收一个List<Widget> children
,我们可以在里面放多个widget。
SliverChildBuilderDelegate:
该函数接收一个NullableIndexedWidgetBuilder builder
,和ListView的itemBuilder
一样。
dart
CustomScrollView(
scrollDirection: Axis.vertical,
slivers: [
SliverList(
delegate: SliverChildListDelegate([
...
])),
SliverList(delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
...
}))
],
)
Step.2
接下来开始添加列表,因为头两个列表是横向滚动,所以把它们都放在第一个SliverList中,为了更加直观,我省略了部分代码。
笔者发现在源码中SliverChildListDelegate有这样的注释:
less
/// In general building all the widgets in advance is not efficient. It is
/// better to create a delegate that builds them on demand using
/// [SliverChildBuilderDelegate] or by subclassing [SliverChildDelegate]
/// directly.
意思是说,SliverChildListDelegate
会一次性创建并渲染所有的子组件,这是没有效率的,更推荐使用SliverChildBuilderDelegate 或者是SliverChildDelegate的子类。
SliverChildListDelegate.build
函数中的代码可以论证这一点,直接返回了children数组中定义的组件。
dart
@override
Widget build(BuildContext context, int index) {
assert(index >= 0);
assert(index < children.length);
return children[index];
}
所以我们在这里添加ListView,因为ListView仅会渲染窗口内的子组件。
dart
CustomScrollView(
scrollDirection: Axis.vertical,
slivers: [
SliverList(
delegate: SliverChildListDelegate([
SizedBox(
height: 200,
child: ListView.builder(
...
);
}),
),
SizedBox(
height: 50,
child: ListView.builder(
...
);
}),
),
])),
SliverList(delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
...
}))
],
)
Step.3
最后我们添加SliverChildBuilderDelegate的builder函数。
less
SliverList(delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
child: BookListItem(),
);
})
最后
这篇文章只是实现了一个较简单的多重滑动布局,如果你解决过更加复杂的滑动布局,有更好的解决方案,欢迎分享在评论区。