解码Flutter(三)ListView嵌套

发布于 2022年 05月 07日 02:07

本篇文章主要来阐述flutter中解决多个ListView嵌套的问题。

ShrinkWrap

当我们使用ListView嵌套多个ListView的时候,我们需要将嵌套的ListViewshrinkWrap属性值设置为trueshrinkWrap属性会强制评估整个内部列表,允许它请求有限的高度,而不是ListView对象的通常高度,即无穷大。

通过下面代码示例,我们来探索ShrinkWrap属性, 本着文章的可读性,本文只引用关键的示例代码

@override
 void initState() {
   super.initState();
   for (int i = 0; i < numLists; i++) {
     final _innerList = <ColorRow>[];
     for (int j = 0; j < numberOfItemsPerList; j++) {
       _innerList.add(const ColorRow());
     }
     innerLists.add(
       ListView.builder(
         itemCount: numberOfItemsPerList,
         itemBuilder: (BuildContext context, int index) => _innerList[index],
         shrinkWrap: true,
         physics: const NeverScrollableScrollPhysics(),
       ),
     );
   }
 }
 
 @override
 Widget build(BuildContext context) {
   return ListView.builder(
       itemCount: numLists,
       itemBuilder: (context, index) => innerLists[index]);
 }
  • 1,shrinkWrap会强制使ListView一次性加载所有的内部子部件,以获取整个ListView内容的整个高度。但这样会占用很大的内寸空间,当数量特别多的时候,会有严重的卡顿等性能问题。

  • 2,NeverScrollableScrollPhysics: 使ListView不可滑动。

嵌套List的懒加载 Slivers

我们可以使用 Slivers让嵌套的ListView里面的小部件进行懒加载。 1,将外层的ListView变成SliverList

 @override
  Widget build(BuildContext context) {
    return CustomScrollView(slivers: innerLists);
  }

2,将 List<ListView>变成List<SliverList>

 List<SliverList> innerLists = [];

3,修改innerLists的初始化方法

@override
  void initState() {
    super.initState();
    for (int i = 0; i < numLists; i++) {
      final _innerList = <ColorRow>[];
      for (int j = 0; j < numberOfItemsPerList; j++) {
        _innerList.add(const ColorRow());
      }
      innerLists.add(
        SliverList(
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) => _innerList[index],
            childCount: numberOfItemsPerList,
          ),
        ),
      );
    }
  }

这样改造就完成了,当我们运行时,并不会将ListView中的所有Widget一次性加载完成,当我们滑动的时候,会动态的去构建大部分Widget。

参考

Nested lists - ShrinkWrap vs Slivers dart pad

ShrikWrap 对比 Slivers

推荐文章