1.问题
关于flutter ListView 会有当列表项目超过可视范围,项目自动销毁的问题。本文就这一问题,结合超级简单的案例,进行说明。
2.原因
ListView 会有当列表项目超过可视范围,之所以会销毁,是因为Flutter 效能的问题,会对ScrollView中可视范围外的项目,进行销毁,当项目回到可视范围内时,又会重新建立。这样做的好处,就是节约资源。(SingleChildScrollView 则不会销毁项目)
但有时候,并不想让ScrollView去做这件事情,比如,你已经从服务器获取的数据,如果再重新建立加载的话,又要重新发送请求,这样显然是更浪费资源的事情。所以我们需要让可视范围之外的项目保持活性,不让Flutter去销毁他们。
3.解决
案例:ListView.builder 在容器高度为250中,创建一个ListView,listVIew的项目就是一个文本框。因为没有给定itemCount,所以滚动这个ListView会一直创建新的列表项目。
Widget build(BuildContext context) {
return Scaffold(
body: Column(children: [
Container(
height: 250,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
print("index:$index");
return Text("data$index");
},
))
]),
);
试着上下滚动这个ListView,你会发现,后台会一直重复创建从可视范围外回来的项目。如何不让这些可视范围的项目被销毁呢,你需要让你的列表项目是一个一直保持活性的项目。实现AutomaticKeepAliveClientMixin 这个混合接口。为了方便日后的复用,我们自定义了一个KeepAliveWrapper (代码如下)。
import 'package:flutter/material.dart';
class KeepAliveWrapper extends StatefulWidget {
const KeepAliveWrapper(
{Key? key, @required this.child, this.keepAlive = true})
: super(key: key);
final Widget? child;
final bool keepAlive;
@override
State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}
class _KeepAliveWrapperState extends State<KeepAliveWrapper>
with AutomaticKeepAliveClientMixin {
@override
Widget build(BuildContext context) {
return widget.child!;
}
@override
bool get wantKeepAlive => widget.keepAlive;
}
此时我们再修改案例的代码,让其构成的项目为保活项目,我们再上下滚动ListView,你会发现,已经创建的项目不会被销毁了。
将案例中的 Text("data$index") 改为 KeepAliveWrapper(child: Text("data$index"))