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

Flutter ListView添加好友按钮点击后全局加载异常问题

问题分析

你用了**单个全局布尔值isLoading**控制所有添加按钮的状态。点击任意按钮时,这个变量被设为true,所有按钮都会读取这个值并切换到加载状态,导致全量按钮显示加载的问题。

解决步骤

把单个isLoading改成按用户uid记录加载状态的集合,用Set<String>存储正在加载的用户uid,精准控制单个按钮的状态:

1. 替换状态变量

在你的State类中,把原来的bool isLoading = false;替换成:

Set<String> loadingUserIds = {};

2. 修改按钮点击逻辑

点击时仅标记当前用户的uid为加载状态,请求完成(成功/失败)后移除该标记:

onTap: () {
  final targetUid = client["uid"];
  setState(() {
    loadingUserIds.add(targetUid);
  });
  PalRequestModel palRequest = PalRequestModel(
    name: ap.userModel.name,
    avatar: ap.userModel.avatar,
    phoneNumber: ap.userModel.phoneNumber,
    uid: ap.userModel.uid,
  );
  ap.sendRequestToPals(
    context: context,
    palRequests: palRequest,
    palId: targetUid,
    onSuccess: () {
      setState(() {
        loadingUserIds.remove(targetUid);
      });
    },
    // 补充错误回调,避免加载状态一直卡住
    onError: (error) {
      setState(() {
        loadingUserIds.remove(targetUid);
      });
    }
  );
},

3. 修改按钮状态判断

将原来的isLoading判断,改成检查当前用户uid是否在loadingUserIds集合中:

child: loadingUserIds.contains(client["uid"])
    ? Padding(
        padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            CustomProgressBar(),
          ],
        ),
      )
    : Row(
        mainAxisSize: MainAxisSize.min,
        children: const [
          Icon(
            Icons.person_add,
            size: 20,
          ),
          SizedBox(
            width: 5,
          ),
          Text(
            "add",
            style: TextStyle(fontSize: 18),
          ),
        ],
      ),

完整核心代码片段

// State类内定义状态变量
Set<String> loadingUserIds = {};

// StreamBuilder内的循环构建部分
for (var client in clients!) {
  final clientWidget = Column(
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      ListTile(
        leading: FadedScaleAnimation(
          child: CircleAvatar(
              radius: 30.0,
              backgroundImage: Image.network(client["avatar"] ??
                      "https://i.pravatar.cc/300")
                  .image),
        ),
        trailing: GestureDetector(
          onTap: () {
            final targetUid = client["uid"];
            setState(() {
              loadingUserIds.add(targetUid);
            });
            PalRequestModel palRequest = PalRequestModel(
              name: ap.userModel.name,
              avatar: ap.userModel.avatar,
              phoneNumber: ap.userModel.phoneNumber,
              uid: ap.userModel.uid,
            );
            ap.sendRequestToPals(
                context: context,
                palRequests: palRequest,
                palId: targetUid,
                onSuccess: () {
                  setState(() {
                    loadingUserIds.remove(targetUid);
                  });
                },
                onError: (error) {
                  setState(() {
                    loadingUserIds.remove(targetUid);
                  });
                });
          },
          child: Container(
              padding: const EdgeInsets.all(5),
              decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(40),
                  border: Border.all(width: 0.8, color: Colors.grey)),
              child: loadingUserIds.contains(client["uid"])
                  ? Padding(
                      padding: const EdgeInsets.symmetric(
                          vertical: 5.0, horizontal: 10.0),
                      child: Row(
                        mainAxisSize: MainAxisSize.min,
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          CustomProgressBar(),
                        ],
                      ),
                    )
                  : Row(
                      mainAxisSize: MainAxisSize.min,
                      children: const [
                        Icon(
                          Icons.person_add,
                          size: 20,
                        ),
                        SizedBox(
                          width: 5,
                        ),
                        Text(
                          "add",
                          style: TextStyle(fontSize: 18),
                        ),
                      ],
                    )),
        ),
        title: Text(
          "${client["name"]}".toLowerCase(),
          overflow: TextOverflow.ellipsis,
          style: TextStyles.h2,
        ),
        subtitle: Text(
          "${client["bio"]}".toLowerCase(),
          overflow: TextOverflow.ellipsis,
          style: TextStyles.bodyText,
        ),
      ),
      Divider(
        height: 0.1,
        thickness: 0.5,
        endIndent: 10,
        indent: 10,
        color: ApplicationColors.offWhite,
      ),
    ],
  );
  clientWidgets.add(clientWidget);
}
注意事项
  • 必须在请求失败的回调中也移除uid,避免因网络问题导致加载状态一直无法清除。
  • 如果你的sendRequestToPals方法没有错误回调,建议补充实现,或者用try/catch包裹请求逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 00:05:04