You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);
          },
        );
      }));
}

修改说明:

  1. 在Consumer内部使用ref.watch(sendRecipeProvider)获取状态,这样当selectedFriend改变时,Consumer会触发重建,更新卡片的边框样式
  2. 点击事件里依然用ref.read()来调用状态方法,因为这里只需要执行操作,不需要监听状态

这样修改后,点击好友卡片时,sendRecipeProvider的状态更新会被Consumer监听,AlertDialog的UI会自动刷新,展示正确的选中状态。

内容的提问来源于stack exchange,提问作者Chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 18:15:56