likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 2

前言

我们在使用ListView嵌套ListView时,我们往往会用shrinkWrap解决Vertical viewport was given unbounded height问题,但是这样也导致了隐藏的性能问题,因为这会使得shrinkWrap为true的ListView内的所有item在初始化时就全部渲染了。如果该组件显示的item有成千上万个会造成明显的性能问题。接下来我通过一个例子探讨一下用CustomScrollView和SliverList组件多方向的滑动布局。

正文部分

我们按照下图中的布局:两个横向的ListView,一个竖向的ListView。通过CustomScrollView来实现它们。

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

代码部分

Step.1

先打好外部框架,因为大体是垂直布局所以加上Axis.vertical,slivers内添加两个SliverList注意:他们的delegate属性实现的函数不同

SliverChildListDelegate:该函数接收一个List<Widget> children,我们可以在里面放多个widget。

SliverChildBuilderDelegate:该函数接收一个NullableIndexedWidgetBuilder builder,和ListView的itemBuilder一样。

CustomScrollView(
  scrollDirection: Axis.vertical,
  slivers: [
    SliverList(
        delegate: SliverChildListDelegate([
        ...
    ])),
    SliverList(delegate: SliverChildBuilderDelegate(
        (BuildContext context, int index) {
            ...
        }))
  ],
)

Step.2

接下来开始添加列表,因为头两个列表是横向滚动,所以把它们都放在第一个SliverList中,为了更加直观,我省略了部分代码。

笔者发现在源码中SliverChildListDelegate有这样的注释:

/// 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数组中定义的组件。

@override
Widget build(BuildContext context, int index) {
  assert(index >= 0);
  assert(index < children.length);
  return children[index];
}

所以我们在这里添加ListView,因为ListView仅会渲染窗口内的子组件。

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函数。

SliverList(delegate: SliverChildBuilderDelegate(
    (BuildContext context, int index) {
  return Padding(
    padding: const EdgeInsets.symmetric(vertical: 5, horizontal: 20),
    child: BookListItem(),
  );
})

最后

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

转载自:https://juejin.cn/post/7359209218900361256
评论
请登录