Flutter 中,ListView 中需要放置 ListView 需要怎么处理才高效?
问题及场景
ListView 是 Flutter 开发者第一个学习到的 Widget,因为它可以滑动。一切都会运行得很好,直到 ListView 中的 Item 本身也是一个 ListView。你可能会看到 Flutter 建议你将内部的 ListView 的ShrinkWrap 属性设置为 True。虽然错误消除了,但是威胁还在。因为 ShrinkWrap 属性会将 ListView 一次性全部填充,算出所有高度,如果内部 ListView 的数据量比较大,那将产生性能问题,会有很大的风险掉帧、jank 和 stutters。
假设你遇到下面这样的场景
final outerListChildren = <ListView>[
ListView(children: <Wdiget>[...]),
...
];
return ListView.Builder(
itemCount: outerListChildren.length,
itemBuilder: (context, index) {
return outerListChildren[index]
}
)
然后我们按照 Flutter 的提示,将内部的 ListView 加上 shrinkWrap 和 physics 属性如下
final outerListChildren = <ListView>[
ListView(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
children: <Wdiget>[...]
),
...
];
return ListView.Builder(
itemCount: outerListChildren.length,
itemBuilder: (context, index) {
return outerListChildren[index]
}
)
解决方法:
1、首先,将最外层的 ListView 改为 CustomScrollView
return CustomScrollView(
children: outerListChildren
}
)
2、然后我们将外部的 ListView 列表改为 SliverList 列表
final outerListChildren = <SliverList>[];
return CustomScrollView(
children: outerListChildren
}
)
3、所有 SliverList 添加 delegate,并使用 SliverChildBuilderDelegate 作为 value,_myWidgets
是之前的 inner ListView 需要显示的内容
final outerListChildren = <SliverList>[
SliverList(
delegate: SliverChildBuilderDelegate(
childCount: _myWidgets.length,
(context, index) => _myWidgets[index]
)
)
];
return CustomScrollView(
children: outerListChildren
}
)
至此,大功告成