ListView.builder() 渲染長列表數據
下面是ListView.builder() 的註釋如下:
/// This constructor is appropriate for list views with a large (or infinite)
/// number of children because the builder is called only for those children
/// that are actually visible.
直接使用 ListView(children: List<Widget>)
的優點是簡單邊界,直接生成一個 List<Widget>
的列表,然後賦值給 ListView
的 children
參數即可
缺點是整個ListView 是沒有回收機制的,會一次性創建出所有的子項,構建完成整個ListView。
這意味著一旦列表長度非常長,比如無限滾動列表的場景中,列表長度非常長,直接創建ListView 的所有子項可能會有內存問題,過高的內存會引起Crash
------------------------------------------------------------------------------------------
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
var rng = Random();
static const loadingTag = "##loading##"; //表尾标记
var _words = <String>[loadingTag];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Scrollbar(
child: ListView.separated(
itemCount: _words.length,
itemBuilder: (context, index) {
//如果到了表尾
if (_words[index] == loadingTag) {
//不足100条,继续获取数据
if (_words.length - 1 < 100) {
//获取数据
_retrieveData();
//加载时显示loading
return Container(
padding: const EdgeInsets.all(16.0),
alignment: Alignment.center,
child: SizedBox(
width: 24.0,
height: 24.0,
child: CircularProgressIndicator(strokeWidth: 2.0),
),
);
} else {
//已经加载了100条数据,不再获取数据。
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Text(
"没有更多了",
style: TextStyle(color: Colors.grey),
),
);
}
}
//显示单词列表项
return ListTile(title: Text(index.toString()+':'+_words[index]));
},
separatorBuilder: (context, index) => Divider(height: .0),
),
),
),
floatingActionButton: FloatingActionButton(
onPressed: (){
},
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
void _retrieveData() {
Future.delayed(Duration(seconds: 2)).then((e) {
setState(() {
_words.insertAll(
_words.length - 1,
//每次生成20个random number
[for(var i=0;i<20;i++) rng.nextInt(100).toString() ] ,
);
});
});
}
}