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

Flutter中如何通过下拉选项选择多个房间组件并更新价格?

问题解决:多房间选择下拉菜单无法添加房间并更新价格

问题现象

尝试通过下拉菜单选择多个房间组件的数量,以此更新总价,但下拉选项变更时,无法将房间正确添加到列表中,功能失效。

房间选择界面

现有代码分析

房间组件(包含Dropdown)代码:

Container(
            padding: EdgeInsets.symmetric(
                horizontal: ScreenUtils.horizontalSpace12!,
                vertical: ScreenUtils.verticalSpace12!),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  "Choose rooms",
                  style: textThemes(context).headlineMedium!.copyWith(
                        fontSize: ScreenUtils.fontSize18!,
                        letterSpacing: -0.8,
                      ),
                ),
                SizedBox(
                  height: ScreenUtils.horizontalSpace8,
                ),
                CustomContainer.rectangle(
                  color: MyColors.dropdownColor,
                  borderColor: MyColors.greyDivider,
                  padding: 0,
                  radius: 4,
                  widget: Consumer<RoomProvider>(
                      builder: (context, value, child) {
                    return Row(
                      children: [
                        Expanded(
                            child: Dropdown(
                                hintText:
                                    "1 (NPR. ${roomlist.pricePerNight})",
                                selectedValue: value.selectedRoomNo,
                                optionList: value.roomNo
                                    .map((e) => DropdownMenuItem(
                                        child: Text(
                                          "$e (NPR. ${calculatePrice(e)})",
                                          style: textThemes(context)
                                              .bodyLarge!
                                              .copyWith(
                                                  fontSize: ScreenUtils
                                                      .fontSize16),
                                        ),
                                        value: e))
                                    .toList(),
                                onchanged: onchanged)),
                      ],
                    );
                  }),
                ),
              ],
            ),
          ),

调用房间组件及Dropdown逻辑代码:

Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text(
        "Select your rooms",
        style: textThemes(context).displayMedium!.copyWith(
            fontSize: ScreenUtils.fontSize20!, letterSpacing: -0.8),
      ),
      SizedBox(
        height: ScreenUtils.verticalSpace16!,
      ),
      SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Consumer<RoomProvider>(builder: (context, value, child) {
            List<Rooms> rooms = value.roomList;

            return Wrap(
              spacing: ScreenUtils.horizontalSpace8!,
              children: [
                ...List.generate(rooms.length, (index) {
                  if (value.isLoading) {
                    return const Center(child: CircularProgressIndicator());
                  } else {
                    if (rooms.isEmpty) {
                      return const Text("data");
                    }
                    if (index == rooms.length) {
                      return SizedBox(
                        width: ScreenUtils.horizontalSpace8,
                      );
                    }
                    return RoomComponent(
                      onchanged: (val) {
                        if (!rooms.contains(val)) {
                          roomsList.add(rooms[index]);
                        }

                        print(rooms);
                        print(rooms.length);

                        // value.changeRoomNo(val);
                        // var selected = val;
                        // // sel.insert(index, selected!);
                        // // print(sel);
                        // sel.add(rooms[index]);
                        // print(sel.length);
                        // var price = sel
                        //     .map((e) => e.pricePerNight)
                        //     .reduce((value, element) => value! + element!);
                        // print(price);
                        // (sel.map((e) => {e.pricePerNight!}));
                        // SelectedRoom selectedRoom = SelectedRoom();

                        // Provider.of<UIHelper>(context, listen: false)
                        //     .calculateTotal(price, int.parse(val!));
                      },
                      roomlist: value.roomList[index],
                    );
                  }
                })
              ],
            );
          })),
    ],
  ),

核心问题点

  1. 下拉选择状态共享冲突:所有RoomComponent共用value.selectedRoomNo全局状态,导致多个房间的下拉选项互相干扰,无法独立控制每个房间的选择数量。
  2. 房间存在判断逻辑错误:rooms.contains(val)中,val是下拉选择的数字(如1、2),而rooms是Rooms对象列表,用数值匹配对象必然判断错误,无法正确过滤重复添加。
  3. 未正确更新状态触发UI刷新:roomsList是局部变量,未通过RoomProvider管理状态,更新后无法通知UI重新渲染,导致列表和价格不更新。
  4. 添加房间逻辑不符合需求:直接添加rooms[index]对象,未关联选择数量,无法正确统计每个房间的订购数和总价。

修复方案

1. 修改RoomProvider,支持多房间独立状态

在RoomProvider中用Map存储每个房间对应的选择数量,替代单个变量:

class RoomProvider extends ChangeNotifier {
  // 存储每个房间ID对应的选择数量
  Map<String, int> selectedRoomCounts = {};
  List<Rooms> roomList = [];
  bool isLoading = false;

  // 更新指定房间的选择数量
  void updateRoomCount(String roomId, int count) {
    selectedRoomCounts[roomId] = count;
    notifyListeners(); // 通知UI刷新
  }

  // 计算总价
  int calculateTotalPrice() {
    int total = 0;
    for (var room in roomList) {
      int count = selectedRoomCounts[room.id] ?? 0;
      total += (room.pricePerNight ?? 0) * count;
    }
    return total;
  }

  // 其他原有逻辑...
}

2. 修改RoomComponent,绑定单个房间的选择状态

每个RoomComponent根据当前房间ID获取对应选择数量,不再共享全局变量:

Container(
  padding: EdgeInsets.symmetric(
      horizontal: ScreenUtils.horizontalSpace12!,
      vertical: ScreenUtils.verticalSpace12!),
  child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text(
        "Choose rooms",
        style: textThemes(context).headlineMedium!.copyWith(
              fontSize: ScreenUtils.fontSize18!,
              letterSpacing: -0.8,
            ),
      ),
      SizedBox(height: ScreenUtils.horizontalSpace8),
      CustomContainer.rectangle(
        color: MyColors.dropdownColor,
        borderColor: MyColors.greyDivider,
        padding: 0,
        radius: 4,
        widget: Consumer<RoomProvider>(
          builder: (context, value, child) {
            // 获取当前房间的已选数量,默认1
            int currentCount = value.selectedRoomCounts[roomlist.id] ?? 1;
            return Row(
              children: [
                Expanded(
                  child: Dropdown(
                    hintText: "1 (NPR. ${roomlist.pricePerNight})",
                    selectedValue: currentCount.toString(),
                    optionList: value.roomNo
                        .map((e) => DropdownMenuItem(
                              child: Text(
                                "$e (NPR. ${calculatePrice(e)})",
                                style: textThemes(context)
                                    .bodyLarge!
                                    .copyWith(fontSize: ScreenUtils.fontSize16),
                              ),
                              value: e.toString(),
                            ))
                        .toList(),
                    onchanged: (val) {
                      if (val != null) {
                        int count = int.parse(val);
                        // 调用Provider更新当前房间的选择数量
                        value.updateRoomCount(roomlist.id, count);
                      }
                    },
                  ),
                ),
              ],
            );
          },
        ),
      ),
    ],
  ),
);

3. 调整父组件,移除错误添加逻辑,直接通过Provider计算总价

不需要维护局部roomsList,直接用RoomProvider的calculateTotalPrice()获取总价:

Column(
  crossAxisAlignment: CrossAxisAlignment.start,
  children: [
    Text(
      "Select your rooms",
      style: textThemes(context).displayMedium!.copyWith(
            fontSize: ScreenUtils.fontSize20!,
            letterSpacing: -0.8,
          ),
    ),
    SizedBox(height: ScreenUtils.verticalSpace16!),
    SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: Consumer<RoomProvider>(
        builder: (context, value, child) {
          List<Rooms> rooms = value.roomList;

          if (value.isLoading) {
            return const Center(child: CircularProgressIndicator());
          }

          if (rooms.isEmpty) {
            return const Text("暂无房间数据");
          }

          return Wrap(
            spacing: ScreenUtils.horizontalSpace8!,
            children: rooms.map((room) {
              return RoomComponent(
                roomlist: room,
                onchanged: (val) {},
              );
            }).toList(),
          );
        },
      ),
    ),
    // 显示总价
    Consumer<RoomProvider>(
      builder: (context, value, child) {
        int total = value.calculateTotalPrice();
        return Text(
          "总价: NPR. $total",
          style: textThemes(context).headlineMedium,
        );
      },
    ),
  ],
);

关键优化点

  • 每个房间的选择状态独立存储,避免下拉选项互相干扰
  • 通过Provider统一管理状态,更新后自动触发UI刷新
  • 总价计算逻辑封装在Provider中,保证数据一致性
  • 移除错误的对象判断逻辑,直接基于房间ID关联选择数量

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 14:47:08