如何更新Flutter列表中的单个项目?我需要最好的方法。为什么我说最好的方法?我需要更新一个单一的项目,不希望当更新一个单一的项目上,所有项目存在于列表中得到渲染。我的意思是,当更新一个项目时,只刷新该项目,而不是整个列表。因为如果整个列表只更新了一个项目,那么我们的应用程序可能不会有很好的性能。那么,有没有办法克服这一点呢?
9w11ddsr1#
这是我的方式
foods[foods.indexWhere((element) => element.uid == food.uid)] = food;
应该应用一些验证来避免任何空引用问题
cwxwcias2#
您可以通过在每个项生成器中嵌套流生成器来实现此目的。这可以通过使用流构建器的initialData参数来实现。
initialData
final Stream<Item> updateItemsSteram = ...; final List<Item> initialList = [...]; ListView.builder( itemBuilder: (context, idx) { return StreamBuilder<Item>( initialData: initialList[idx], stream: updateItemsSteram.where((item) => item.id == initialList[idx].id), builder: (ctx, snapshot) => MyCustomWidget(snapshot.data) ); } )
不过,您可能希望对此进行基准测试,并将其与更新整个列表进行比较,因为flutter在所有情况下都会重用元素,而流可能会带来更多开销。
8xiog9wr3#
如果您有大量的项,那么将setState()与ListView.builder()一起使用会更快。例如:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { List<int> ids = []; initState() { super.initState(); for (var i = 0; i < 100; i++) { ids.add(i); } new Future.delayed(Duration(seconds: 3)).then((_) { setState(() { ids[4] = 1000; }); }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar(), body: ListView.builder( itemCount: ids.length, itemBuilder: (context, idx) { return ListTile(title: Text('${ids[idx]}')); }, ), ), ); } }
查看ListView.builder docs以了解更多详细信息。
lnlaulya4#
我用一个statefull小部件来表示ListView中的一个项,从而解决了这个问题。如果您只想操作一个项目数据,您可以通过Item小部件来完成。如果你在列表的尾部添加或删除一个项目,列表将不会被重新呈现。
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:english_words/english_words.dart'; import 'package:random_color/random_color.dart'; RandomColor randomColor = RandomColor(); void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { final wordPair = WordPair.random(); // Add this line. return MaterialApp( title: 'Welcome to Flutter', home: Numbers(), debugShowCheckedModeBanner: false, ); } } /** * View */ class Numbers extends StatefulWidget { @override State<StatefulWidget> createState() { return NumbersState(); } } /** * Item */ class Item extends StatefulWidget { int value; Item({this.value}); @override State<StatefulWidget> createState() { // TODO: implement createState return ItemState(); } } class ItemState extends State<Item> { @override Widget build(BuildContext context) { return Container( color: randomColor.randomColor(colorBrightness: ColorBrightness.light), child: ListTile( title: Text(widget.value.toString()), onTap: () { setState(() { widget.value++; }); }, ), ); } } /** * List */ class NumbersState extends State<Numbers> { List<Item> numbers = new List<Item>(); String message = "Teste"; void addItem(int v) { Item i = Item(value: v,); numbers.add(i); setState(() {}); } Stream generateNumbers() async* { for (int i in List.generate(5, (i) => i)) { yield i; } } @override void initState() { // super.initState(); generateNumbers().listen((dynamic i) { print(i); Timer(Duration(seconds: 0), () { addItem(i); }); }); } @override Widget build(BuildContext context) { return Scaffold( // Add from here... appBar: AppBar( title: Text('ListView'), actions: <Widget>[ IconButton( icon: Icon(Icons.ac_unit), onPressed: () { setState(() { message = "Teste"; }); }, ), IconButton( icon: Icon(Icons.arrow_upward), onPressed: () { setState(() { message = "Teste"; }); }, ), IconButton( icon: Icon(Icons.arrow_downward), onPressed: () { setState(() { message = "Teste"; }); }, ), IconButton( icon: Icon(Icons.add), onPressed: () { addItem(1); }, ), IconButton( icon: Icon(Icons.remove), onPressed: () { numbers.removeAt(numbers.length-1); setState(() {}); }, ) ], ), body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ Container( padding: EdgeInsets.all(16), child: Text("Teste de ListView: \n 1. Atualizar item\n 2. Navegação\n 3. Movimento"), ), Expanded( child: ListView.builder( reverse: true, itemCount: numbers.length, itemBuilder: (context, int i) { return numbers[i]; }) ) ], ), ); // ... to here. } }
vxbzzdmp5#
您可以使用这种易于阅读的优化方式访问对象:
foods.firstWhere((element) => element.id == searchedId) = food;
而不是这个
b0zn9rqh6#
如果你知道索引,那么你可以很容易地改变其相应项的值。如果你不知道索引,那么首先使用indexOf(E element, [int start = 0])方法从值中获取索引。然后按如下方式更改该值。
indexOf(E element, [int start = 0])
List<int> list = [1, 2]; growableList[0] = 87;
hujrc8aj7#
一个简单的方法是list[index]=updatevalue
cclgggtu8#
如果你确定名单上有你的目标。
如果你不确定。
for (int i = 0; i < foods.length; i++) { if (foods[i].id != searchedId) continue; foods[i] = food; break; }
警告,如果您的目标不存在,firstWhere和indexWhere可能会出错。或在使用这些溶液之前使用它。
firstWhere
indexWhere
bool found = foods.contains((food) => food.id == newFood.id);
8条答案
按热度按时间9w11ddsr1#
这是我的方式
应该应用一些验证来避免任何空引用问题
cwxwcias2#
您可以通过在每个项生成器中嵌套流生成器来实现此目的。这可以通过使用流构建器的
initialData
参数来实现。不过,您可能希望对此进行基准测试,并将其与更新整个列表进行比较,因为flutter在所有情况下都会重用元素,而流可能会带来更多开销。
8xiog9wr3#
如果您有大量的项,那么将setState()与ListView.builder()一起使用会更快。例如:
查看ListView.builder docs以了解更多详细信息。
lnlaulya4#
我用一个statefull小部件来表示ListView中的一个项,从而解决了这个问题。如果您只想操作一个项目数据,您可以通过Item小部件来完成。如果你在列表的尾部添加或删除一个项目,列表将不会被重新呈现。
vxbzzdmp5#
您可以使用这种易于阅读的优化方式访问对象:
而不是这个
b0zn9rqh6#
如果你知道索引,那么你可以很容易地改变其相应项的值。如果你不知道索引,那么首先使用
indexOf(E element, [int start = 0])
方法从值中获取索引。然后按如下方式更改该值。hujrc8aj7#
一个简单的方法是list[index]=updatevalue
cclgggtu8#
如果你确定名单上有你的目标。
如果你不确定。
警告,如果您的目标不存在,
firstWhere
和indexWhere
可能会出错。或在使用这些溶液之前使用它。