【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(),
  );
})

最后

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

相关推荐
chenyin4 小时前
Flutter 架构设计:Feature-First 与 Pub workspaces
flutter
gnip4 小时前
GetX 在 Flutter 中的使用:两种视图管理方式解析
前端·flutter
程序员老刘4 小时前
Flutter版本选择指南:9月大限落地,3.47一个月连发四补丁 | 2026年9月
flutter·ai编程·客户端
zeqinjie5 小时前
Flutter 获取 iPhone Duo 预留区位置
前端·flutter·ios
恋猫de小郭5 小时前
Flutter Golden Tests:给 AI Agent 的 UI 测试系统
android·前端·flutter
CHB5 小时前
一文讲透原生渲染和自渲染
flutter·react native·uni-app
君赏6 天前
棉宇宙 Flutter 热更新是如何落地的
flutter
恋猫de小郭6 天前
AndroidX 新增 Security State ,支持可编程的系统安全状态查询
android·前端·flutter
zihan5186 天前
自己做软件日记9/21 得到了一个良好的文件结构框架
后端·flutter·前端框架·android studio
ZFJ_张福杰7 天前
【Flutter】Flutter 中有哪些耗时操作?从 UI 卡顿到 Isolate 性能优化
flutter·性能优化·卡顿·isolate