【问题标题】:How to increase quantity of same item click in Flutter (Bloc)如何在 Flutter(Bloc)中增加相同项目的点击量
【发布时间】:2022-01-19 09:27:26
【问题描述】:

HomePage.dart 中,我使用http 包和flutter_bloc 获取api 数据用于架构。现在,一旦我获得数据并且如果我选择 HomePage.dart 中的任何项目,那么它将被添加到 MenuCart.dart 中。现在我面临的问题是

  1. 如果我多次单击同一项目,则会显示重复的 card 小部件。
  2. MenuCart.dart 中,我添加了两个按钮+-,我将数量增加到3,然后我决定删除该项目。现在我回到上一个屏幕,再次添加相同的项目,如果我转到MenuCart.dart,则数量显示4

我的期望

  1. 它不应该生成重复的card,而是数量应该增加。
  2. 在我删除一个项目并再次添加相同的项目后,数量必须显示1

HomePage.dart 中,由于冗长,我显示的代码数量非常有限,但我添加了 bloc 和 MenuCart.dart 的代码。

HomePage.dart

GestureDetector(
                                    onTap: () {
                                      BlocProvider.of<MenuCartBloc>(context)
                                          .add(AddToCart(data[index])); // Here adding an item in MenuCart
                                    },
                                    child: Container(
                                      child: Center(
                                        child: Padding(
                                          padding: const EdgeInsets.all(4.5)
                                          child: Text('ADD'),
                                        ),
                                      ),
                                    ),
                                  );

DishMenuTypesId.dart(模型)

class DishMenuTypesIdData {
  String? id;
  int? status;
  int? quantity;
  String? dishPrice;
  String? photo;

  DishMenuTypesIdData({
    this.id,
    this.status,
    this.quantity = 1,
    this.dishPrice,
    this.photo,
  });
  DishMenuTypesIdData.fromJson(Map<String, dynamic> json) {
    id = json['id']?.toString();
    status = json['status']?.toInt();
    quantity = 1;
    dishPrice = json['dish_price']?.toString();
    photo = json['photo']?.toString();
  }
  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['id'] = id;
    data['status'] = status;
    data["quantity"] = quantity;
    data['dish_price'] = dishPrice;
    data['photo'] = photo;
    return data;
  }
}

class DishMenuTypesId {
  String? message;
  List<DishMenuTypesIdData?>? data;

  DishMenuTypesId({
    this.message,
    this.data,
  });
  DishMenuTypesId.fromJson(Map<String, dynamic> json) {
    message = json['message']?.toString();
    if (json['data'] != null) {
      final v = json['data'];
      final arr0 = <DishMenuTypesIdData>[];
      v.forEach((v) {
        arr0.add(DishMenuTypesIdData.fromJson(v));
      });
      this.data = arr0;
    }
  }
  Map<String, dynamic> toJson() {
    final data = <String, dynamic>{};
    data['message'] = message;
    if (this.data != null) {
      final v = this.data;
      final arr0 = [];
      v!.forEach((v) {
        arr0.add(v!.toJson());
      });
      data['data'] = arr0;
    }
    return data;
  }
}

MenuCartBloc.dart

class MenuCartBloc extends Bloc<MenuCartEvent, MenuCartState> {
  MenuCartBloc() : super(MenuLoaded([]));

  List<DishMenuTypesIdData> cart = [];

  @override
  Stream<MenuCartState> mapEventToState(
    MenuCartEvent event,
  ) async* {
    yield MenuLoading();
    try {
      if (event is AddToCart) {
        final itemExist = cart.where((e) => e.id == event.dish.id);
        if (itemExist.isNotEmpty) {
          print("Not Empty"); // Here i am expecting to show qty 2 if i click an item more than 1 time
        } else {
          print("Empty");
          cart.add(event.dish);
        }
      } else if (event is DeleteToCart) {
        cart.remove(event.dish);
      } else if (event is ClearAllCart) {
        cart = [];
      }
      yield MenuLoaded(cart);
    } catch (e) {
      yield MenuFailed(e.toString());
    }
  }
}

MenuCartEvent.dart

abstract class MenuCartEvent {}

class AddToCart extends MenuCartEvent {
  late final DishMenuTypesIdData dish;
  AddToCart(this.dish);
}
class DeleteToCart extends MenuCartEvent {
  late final DishMenuTypesIdData dish;
  DeleteToCart(this.dish);
}
class ClearAllCart extends MenuCartEvent {}

MenuCartState.dart

abstract class MenuCartState {}

class MenuLoading extends MenuCartState {}

class MenuLoaded extends MenuCartState {
  final List<DishMenuTypesIdData> cart;

  MenuLoaded(this.cart);
}

class MenuFailed extends MenuCartState {
  final String message;

  MenuFailed(this.message);
}

MenuCart.dart

Widget build(BuildContext context) {
    var height = MediaQuery.of(context).size.height;
    var width = MediaQuery.of(context).size.width;
    var lang = translator.activeLanguageCode;
    return Container(
      child: Padding(
          padding: const EdgeInsets.only(top: 20.0, left: 10.0, right: 10.0),
          child: BlocBuilder<MenuCartBloc, MenuCartState>(
            builder: (context, state) {
              DishMenuTypesIdData _cart = DishMenuTypesIdData();
              if (state is MenuLoading) {
                return PlatformCircularProgressIndicator();
              } else if (state is MenuLoaded) {
                return SingleChildScrollView(
                  child: Column(
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text(
                            'Your Reservation Details'.tr(),
                            style: TextStyle(
                                color: TuxedoColor.blackColor,
                                fontSize: lang == "en" ? 14.0 : 15.0,
                                fontFamily: lang == "en"
                                    ? 'OpenSansBold'
                                    : 'ArabicSemiBold'),
                          ),
                          GestureDetector(
                            onTap: () {
                              BlocProvider.of<MenuCartBloc>(context)
                                  .add(ClearAllCart());
                            },
                            child: Row(
                              children: [
                                Icon(
                                  Icons.close,
                                  color: TuxedoColor.redColor,
                                  size: 15.0,
                                ),
                                Text(
                                  'Clear All'.tr(),
                                  style: TextStyle(
                                      color: TuxedoColor.redColor,
                                      fontSize: 12.0,
                                      fontFamily: lang == "en"
                                          ? 'OpenSansRegular'
                                          : 'ArabicLight'),
                                ),
                              ],
                            ),
                          )
                        ],
                      ),
                      SizedBox(
                        height: 25.0,
                      ),
                      Container(
                        height: height * 0.3,
                        child: ListView.builder(
                            shrinkWrap: true,
                            scrollDirection: Axis.vertical,
                            itemCount: state.cart.length,
                            itemBuilder: (BuildContext context, int index) {
                              _cart = state.cart[index];
                              return Dismissible(
                                key: UniqueKey(),
                                background: Container(
                                  alignment: AlignmentDirectional.centerEnd,
                                  color: TuxedoColor.redBrightColor,
                                  child: Padding(
                                    padding: const EdgeInsets.all(8.0),
                                    child: Icon(
                                      Icons.delete,
                                      color: TuxedoColor.whiteColor,
                                    ),
                                  ),
                                ),
                                onDismissed: (direction) {
                                  BlocProvider.of<MenuCartBloc>(context)
                                      .add(DeleteToCart(_cart));
                                  setState(() {
                                    state.cart.removeAt(index);
                                  });
                                },
                                direction: DismissDirection.endToStart,
                                child: Card(
                                  child: Row(
                                    children: [
                                      Stack(
                                        children: [
                                          ClipRRect(
                                            borderRadius:
                                                BorderRadius.circular(10.0),
                                            child: CachedNetworkImage(
                                              imageUrl:
_cart.photo!,
                                              placeholder: (context, url) => Center(
                                                  child:
                                                      PlatformCircularProgressIndicator()),
                                              errorWidget:
                                                  (context, url, error) =>
                                                      Icon(Icons.error),
                                              width: width * 0.25,
                                              height: height * 0.1,
                                              fit: BoxFit.fill,
                                            ),
                                          ),
                                          Positioned(
                                            bottom: 0,
                                            right: 0,
                                            child: Container(
                                              decoration: BoxDecoration(
                                                  color: TuxedoColor.redColor,
                                                  borderRadius: lang == "en"
                                                      ? BorderRadius.only(
                                                          bottomRight:
                                                              Radius.circular(
                                                                  10),
                                                        )
                                                      : BorderRadius.only(
                                                          bottomLeft:
                                                              Radius.circular(
                                                                  10),
                                                        )),
                                              height: 25.0,
                                              width: 45.0,
                                              child: Padding(
                                                padding: const EdgeInsets.only(
                                                    left: 3.0, right: 3.0),
                                                child: FittedBox(
                                                  fit: BoxFit.fitWidth,
                                                  child: Text(
                                                    '${_cart.dishPrice!} \SR',
                                                    style: TextStyle(
                                                        color: TuxedoColor
                                                            .whiteColor,
                                                        fontFamily: lang == "en"
                                                            ? 'OpenSansSemiBold'
                                                            : 'ArabicSemiBold'),
                                                  ),
                                                ),
                                              ),
                                            ),
                                          )
                                        ],
                                      ),
                                      Padding(
                                        padding:
                                            const EdgeInsets.only(left: 10.0),
                                        child: Column(
                                          children: [
                                            Container(
                                              width: width * 0.6,
                                              child: Row(
                                                mainAxisAlignment:
                                                    MainAxisAlignment
                                                        .spaceBetween,
                                                children: [
                                                  Container(
                                                    height: 25.0,
                                                    child: Row(
                                                      children: [
                                                        MaterialButton(
                                                          color: TuxedoColor
                                                              .redColor,
                                                          shape: CircleBorder(),
                                                          onPressed: () {
                                                            setState(() {
                                                              var minus = state
                                                                  .cart[index]
                                                                  .quantity;
                                                              if (minus !=
                                                                  null) {
                                                                minus--;
                                                                state
                                                                    .cart[index]
                                                                    .quantity = minus;
                                                              }
                                                            });
                                                          },
                                                          child: Text(
                                                            '-',
                                                            style: TextStyle(
                                                                color: Colors
                                                                    .white,
                                                                fontSize: 20),
                                                          ),
                                                        ),
                                                        Text(_cart.quantity
                                                            .toString()),
                                                        MaterialButton(
                                                          color: TuxedoColor
                                                              .redColor,
                                                          shape: CircleBorder(),
                                                          onPressed: () {
                                                            setState(() {
                                                              var add = state
                                                                  .cart[index]
                                                                  .quantity;
                                                              if (add != null) {
                                                                add++;
                                                                state
                                                                    .cart[index]
                                                                    .quantity = add;
                                                              }
                                                            });
                                                          },
                                                          child: Text(
                                                            '+',
                                                            style: TextStyle(
                                                                color: Colors
                                                                    .white,
                                                                fontSize: 20),
                                                          ),
                                                        ),
                                                      ],
                                                    ),
                                                  ),
                                                  GestureDetector(
                                                    onTap: () {
                                                      BlocProvider.of<
                                                                  MenuCartBloc>(
                                                              context)
                                                          .add(DeleteToCart(
                                                              state.cart[
                                                                  index]));
                                                    },
                                                    child: Icon(
                                                      Icons.delete,
                                                      color:
                                                          TuxedoColor.redColor,
                                                    ),
                                                  )
                                                ],
                                              ),
                                            ),
                                            SizedBox(
                                              height: 15.0,
                                            )
                                          ],
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              );
                            }),
                      ),
                    ],
                  ),
                );
              } else if (state is MenuFailed) {
                return Center(child: Text(state.message));
              }
              return Container();
            },
          )),
    );
  }

【问题讨论】:

    标签: flutter http dart flutter-bloc


    【解决方案1】:

    类似的东西应该可以工作:

    final itemExist = cart.firstWhere((e) => e.id == event.dish.id, orElse: () => null);
        if (itemExist != null) {
          itemExist.quantity++;
          print("Not Empty"); // Here i am expecting to show qty 2 if i click an item more than 1 time
        } else {
          print("Empty");
          cart.add(event.dish);
        }
    

    基本上,我们需要检查购物车是否已经有一个具有相同id 的菜。如果购物车包含带有 id 的菜品,我们会增加菜品数量,否则我们只需将菜品添加到购物车中。

    除此之外,我发现您的代码存在潜在问题。 Bloc 正常工作需要创建新的模型实例或正确实施equalshashCode。因此,即使是上面的代码也可能由于这个问题而无法正常工作。请注意它。您可以使用此package 修复它。

    【讨论】:

      猜你喜欢
      • 2021-07-09
      • 2019-12-10
      • 1970-01-01
      • 2020-12-29
      • 2019-06-28
      • 2022-10-23
      • 2019-09-25
      • 2021-01-29
      • 1970-01-01
      相关资源
      最近更新 更多