【flutter小记】使用CustomScrollView和SliverList解决ListView嵌套问题

前言

我们在使用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(),
  );
})

最后

这篇文章只是实现了一个较简单的多重滑动布局,如果你解决过更加复杂的滑动布局,有更好的解决方案,欢迎分享在评论区。

相关推荐
xcyxiner12 小时前
flutter wsl2安装记录(使用宿主机虚拟机)
前端·flutter
Kevin Coding14 小时前
JsonConvert:适用于 Android、鸿蒙与 Flutter 的 JSON 转 Model 插件
android·flutter·harmonyos
iFlyCai1 天前
Flutter原理深度解析:从架构到渲染的全面剖析(二)
flutter·flutter 三棵树
里欧跑得慢1 天前
CSS 模块化架构的演进:BEM、CSS Modules 到 CSS-in-JS 的反思
前端·css·flutter·web·css-in-js
iFlyCai2 天前
深入理解Flutter:StatefulWidget生命周期全解析(一)
flutter·dart·状态管理·statefulwidget
xiangxiongfly9152 天前
Flutter video_player总结
flutter·video_player·chewie
见山是山-见水是水2 天前
鸿蒙版 Flutter Video 视频播放组件:播放控制、全屏切换与倍速播放
flutter·音视频·harmonyos
六年码农3 天前
2026最新开源 屏译ScreenTranslator 0.4.4 开源 全屏实时翻译教程
运维·人工智能·flutter·开源
WeiAreYoung3 天前
Flutter+iOS 实现 Live Activity
flutter·ios
恋猫de小郭3 天前
超好用 R8 Configuration Analyzer, 优化你的 App 大小和内存
android·前端·flutter