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

最后

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

相关推荐
●VON7 小时前
Flutter 鸿蒙插件适配实战:用 clipboard_watcher 0.3.0 监听剪贴板变化
flutter·华为·harmonyos
天空之城--10 小时前
Flutter Drift 完全指南:从原理到实战
jvm·flutter·oracle
yume_sibai14 小时前
02-Flutter进阶开发
前端·flutter
●VON16 小时前
Flutter 鸿蒙插件适配实战:用 is_lock_screen 2.0.0 判断真实锁屏状态
flutter·华为·harmonyos
●VON17 小时前
Flutter 鸿蒙插件适配实战:用 flutter_timezone_observer 1.2.0 监听系统时区变化
flutter·华为·harmonyos
●VON18 小时前
Flutter 鸿蒙 app_install_date 0.1.5 使用实战:读取应用安装时间
flutter·华为·harmonyos
●VON19 小时前
Flutter 鸿蒙插件适配实战:flutter_screenshot_detect 0.1.7 截图事件监听
flutter·华为·harmonyos·鸿蒙
西西学代码2 天前
尾灯-应用层通信协议(BLE)
flutter
恋猫de小郭2 天前
iPhone Duo 适配详解,需要改变的不止是布局模型
前端·flutter·ios