Flutter ListView 不使用 setState() 刷新 UI,尽管 itemCount 和附加列表正确更新
Posted
技术标签:
【中文标题】Flutter ListView 不使用 setState() 刷新 UI,尽管 itemCount 和附加列表正确更新【英文标题】:Flutter ListView doesn't refresh UI with setState(), although itemCount and attached list update correctly 【发布时间】:2020-03-14 03:21:11 【问题描述】:我看到很多人有非常相似的问题,但我尝试的任何方法都不起作用。
上下文
我有一个收藏的想法列表。每当我单击ideaItem 内的按钮时,它都会从列表中删除。
问题
当我删除任何ideaItem 时,屏幕上的最后一个总是被删除,而不是我点击的那个。我的 FavoriteIdeasListView 似乎正确更新了项目数,这意味着附加的列表有效,但 UI 没有重绘 ideaItems。
我已经尝试过什么
一开始我直接在ideaItem 上有删除功能,我读到我应该做一个VoidCallback 并处理从列表本身删除,所以它会注意到变化。没用
我也尝试过使用 Stream Builder,因此流会通知 ListView 刷新。也没用
我尝试一直调用 SetState 并且它没有重新加载,它只是在 initialState 的开头构建列表。
class FavoritesList extends StatefulWidget
FavoritesList(Key key) : super(key: key);
@override
_FavoritesListState createState() => _FavoritesListState();
class _FavoritesListState extends State<FavoritesList>
List<Idea> _favorites = [];
@override
void initState()
super.initState();
favoritesInitialState();
Future <void> favoritesInitialState() async
List<Idea> ideas = await IdeasDB.db.ideas();
setState(()
_favorites = ideas;
);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
title: Text('Favorites')),
body: Center(
child: ListView.builder(
itemCount: _favorites.length,
itemBuilder: (context, index)
final idea = _favorites[index];
return IdeaItem(
idea: idea,
onFavoriteToggle: () => deleteFromFavorites(idea),
);
,
),
)
);
void deleteFromFavorites(Idea idea) async
await IdeasDB.db.deleteIdea(idea.url);
List<Idea> newIdeas = await IdeasDB.db.ideas();
setState(()
this._favorites = newIdeas;
);
【问题讨论】:
【参考方案1】:尝试改变
onFavoriteToggle: () => deleteFromFavorites(index),
然后
void deleteFromFavorites( int index) async
await IdeasDB.db.deleteIdea(idea.url);
setState(()
this._favorites.removeAt(index);
);
看看它是否有效。如果是,deleteIdea()
上可能有错误。
此外,您知道应该删除哪个项目,因此您无需等待从数据库中重新加载列表。 await IdeasDB.db.ideas();
如果您想确保可以使用 Try catch 包装您的代码
void deleteFromFavorites(int index) async
try
await IdeasDB.db.deleteIdea(idea.url);
setState(()
this._favorites.removeAt(index);
);
catch (_)
print('ERROR');
【讨论】:
解决方案是传递 'key' 参数。我赞成,因为优化解决方案消除了不必要的等待!谢谢!【参考方案2】:对于为什么会发生这种情况,我只能看到两种可能的选择。
第一个很明显,您的IdeasDB.db.deleteIdea(idea.url);
没有从数据库中删除正确的想法;
第二个不太明显,这是因为您的元素树无法识别您要删除的小部件是什么。它只发生在有状态的小部件上,就像您的 IdeaItem
一样。
然后解决方案是为您的IdeaItem
小部件使用key
属性
像这样:
ListView.builder(
itemCount: _favorites.length,
itemBuilder: (context, index)
final idea = _favorites[index];
return IdeaItem(
key: ValueKey(idea.url) // or UniqueKey()
idea: idea,
onFavoriteToggle: () => deleteFromFavorites(idea),
);
,
),
在您的 IdeaItem
小部件中,您必须将该密钥传递给您的父级 Stateful widget
,如下例所示:
class IdeaItem extends StatefulWidget
final Idea idea;
Function onFavoriteToggle;
IdeaItem(Key key, this.idea, this.onFavoriteToggle) : super(key: key);
@override
_IdeaItemState createState() => _IdeaItemState();
【讨论】:
有效!解决方案是添加密钥,因为我的 IdeaItem 确实也是有状态的!太棒了!以上是关于Flutter ListView 不使用 setState() 刷新 UI,尽管 itemCount 和附加列表正确更新的主要内容,如果未能解决你的问题,请参考以下文章
flutter listview item滚出屏幕不重置状态
Flutter—ListView嵌套ListView不显示的问题
Flutter—ListView嵌套ListView不显示的问题