我怎么動態地更新 ListView?
在 iOS 中,你改變列表的數據,並通過 reloadData() 方法來通知 table 或是 collection view。
在 Flutter 中,如果你想通過 setState() 方法來更新 widget 列表,你會很快發現你的數據展示並沒有變化。這是因為當 setState() 被調用時,Flutter 渲染引擎會去檢查 widget 樹來查看是否有什么地方被改變了。當它得到你的 ListView 時,它會使用一個 == 判斷,並且發現兩個 ListView 是相同的。沒有什么東西是變了的,因此更新不是必須的。
一個更新 ListView 的簡單方法是,在 setState() 中創建一個新的 list,並把舊 list 的數據拷貝給新的 list。雖然這樣很簡單,但當數據集很大時,並不推薦這樣做:
一個推薦的、高效的且有效的做法是,使用 ListView.Builder 來構建列表。這個方法在你想要構建動態列表,或是列表擁有大量數據時會非常好用。
import 'package:flutter/material.dart'; void main() { runApp(SampleApp()); } class SampleApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Sample App', theme: ThemeData( primarySwatch: Colors.blue, ), home: SampleAppPage(), ); } } class SampleAppPage extends StatefulWidget { SampleAppPage({Key key}) : super(key: key); @override _SampleAppPageState createState() => _SampleAppPageState(); } class _SampleAppPageState extends State<SampleAppPage> { List widgets = []; @override void initState() { super.initState(); for (int i = 0; i < 100; i++) { widgets.add(getRow(i)); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text("Sample App"), ), body: ListView.builder( itemCount: widgets.length, itemBuilder: (BuildContext context, int position) { return getRow(position); }, ), ); } Widget getRow(int i) { return GestureDetector( child: Padding( padding: EdgeInsets.all(10.0), child: Text("Row $i"), ), onTap: () { setState(() { widgets.add(getRow(widgets.length + 1)); print('row $i'); }); }, ); } }
與創建一個 “ListView” 不同,創建一個 ListView.builder 接受兩個主要參數:列表的初始長度,和一個 ItemBuilder 方法。
ItemBuilder 方法和 cellForItemAt 代理方法非常類似,它接受一個位置,並且返回在這個位置上你希望渲染的 cell。
最后,也是最重要的,注意 onTap() 函數里並沒有重新創建一個 list,而是 .add 了一個 widget。
