Flutter/Riverpod中AlertDialog状态变更不更新UI的解决问询
问题
开发一个可选择好友并发送内容的AlertDialog,采用Riverpod管理选中好友的状态。已实现SendRecipe ChangeNotifierProvider维护选中索引,但点击好友卡片后,AlertDialog未更新UI展示选中状态,仅热重载后显示正常。相关代码如下:
final sendRecipeProvider = ChangeNotifierProvider((ref) => SendRecipe()); class SendRecipe extends ChangeNotifier { int selectedFriend = -1; void selectFriend(int index) { if (selectedFriend == index) { selectedFriend = -1; notifyListeners(); return; } selectedFriend = index; notifyListeners(); } }
Widget shareDialog(BuildContext context, Recipe recipe) { return AlertDialog( title: Row( children: [ Text("Text"), const Spacer(), IconButton(onPressed: () {}, icon: const Icon(Icons.send)), //Button to send the content to the selected friend ], ), content: alertContent(context), ); } alertContent(BuildContext context) { return Container( constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.8), width: MediaQuery.of(context).size.width * 0.8, child: Column( mainAxisSize: MainAxisSize.min, children: [ const Divider(), Consumer(builder: (context, ref, child) { return ListView.builder( shrinkWrap: true, itemCount: ref.watch(currentUserProvider).value!.friends.length, itemBuilder: (context, index) { return friendSelectionCard(index); }, ); }), ], ), ); } Widget friendSelectionCard(int index) { return Padding( padding: const EdgeInsets.all(8.0), child: Consumer(builder: (context, ref, child) { return GestureDetector( child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15.0), side: selectedSide(index, ref.read(sendRecipeProvider).selectedFriend), ), child: Padding( padding: const EdgeInsets.all(8.0), child: Row(children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: Icon(Icons.person)), Text(ref .watch(currentUserProvider) .value! .friends[index] .name), ]), ), ), onTap: () { ref.read(sendRecipeProvider).selectFriend(index); }, ); })); } BorderSide selectedSide(int index, int selectedFriend) { if (selectedFriend == index) { return const BorderSide(color: Colors.blue, width: 2); } else { return const BorderSide(color: Colors.transparent, width: 2); } }
解决方案
核心问题是friendSelectionCard里用ref.read()获取选中状态,ref.read()仅读取一次状态值,不会监听后续的状态变更,导致状态更新时UI无法自动重建。只需将ref.read()替换为ref.watch(),让Consumer监听sendRecipeProvider的状态变化即可。
修改后的friendSelectionCard代码如下:
Widget friendSelectionCard(int index) { return Padding( padding: const EdgeInsets.all(8.0), child: Consumer(builder: (context, ref, child) { // 用watch替代read,监听状态变化 final sendRecipeState = ref.watch(sendRecipeProvider); return GestureDetector( child: Card( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15.0), side: selectedSide(index, sendRecipeState.selectedFriend), ), child: Padding( padding: const EdgeInsets.all(8.0), child: Row(children: [ const Padding( padding: EdgeInsets.symmetric(horizontal: 8), child: Icon(Icons.person)), Text(ref .watch(currentUserProvider) .value! .friends[index] .name), ]), ), ), onTap: () { // 操作状态仍用read,因为不需要监听 ref.read(sendRecipeProvider).selectFriend(index); }, ); })); }
修改说明:
- 在Consumer内部使用
ref.watch(sendRecipeProvider)获取状态,这样当selectedFriend改变时,Consumer会触发重建,更新卡片的边框样式 - 点击事件里依然用
ref.read()来调用状态方法,因为这里只需要执行操作,不需要监听状态
这样修改后,点击好友卡片时,sendRecipeProvider的状态更新会被Consumer监听,AlertDialog的UI会自动刷新,展示正确的选中状态。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

