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

最后

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

相关推荐
孤鸿玉8 小时前
Fluter InteractiveViewer 与ScrollView滑动冲突问题解决
flutter
叽哥15 小时前
Flutter Riverpod上手指南
android·flutter·ios
BG1 天前
Flutter 简仿Excel表格组件介绍
flutter
zhangmeng1 天前
FlutterBoost在iOS26真机运行崩溃问题
flutter·app·swift
恋猫de小郭1 天前
对于普通程序员来说 AI 是什么?AI 究竟用的是什么?
前端·flutter·ai编程
卡尔特斯1 天前
Flutter A GlobalKey was used multipletimes inside one widget'schild list.The ...
flutter
w_y_fan2 天前
Flutter 滚动组件总结
前端·flutter
醉过才知酒浓2 天前
Flutter Getx 的页面传参
flutter
火柴就是我3 天前
flutter 之真手势冲突处理
android·flutter
Speed1233 天前
`mockito` 的核心“打桩”规则
flutter·dart