带有 GridView Builder 的提供者

Vas*_*014 5 mvvm dart flutter gridle flutter-provider

我正在制作一个在线商店,其中在 mvvm 架构上有折扣部分和产品类别,目标是更改添加到购物车的产品数量,除了所有产品的数量发生变化外,一切正常,但所有内容都会显示在数据库中正确,我确信在某个地方我错过了一些重要的东西,我将不胜感激的答案,我将在下面附上屏幕截图

\n

根页

\n
return MultiProvider(\n    providers: [\n      ChangeNotifierProvider(\n        create: (context) => MainPageListViewModel(),\n      ),\n      ChangeNotifierProvider(\n          create: (context) => CartViewModel(),\n          child: CartPage()\n      ),\n      ChangeNotifierProvider(\n        create: (context) => AllGoodsViewModel(),\n      ),\n    ],\n  child: MaterialApp(\n      initialRoute: \'/\',\n      routes: {\n        \'/ProfilePage\': (context) => ProfilePage(),\n        \'/MainPage\': (context) => MainPage(),\n        \'/CartPage\': (context) =>   CartPage(),\n      },\n      builder: (context, widget) {\n        return ScreenUtilInitService(\n            builder: (context) => widget!\n        );\n      },\n      title: \'Flutter Demo\',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: present != null ? present : MainPage()\n  ),\n);\n
Run Code Online (Sandbox Code Playgroud)\n

类别页面

\n
class AllCategoryGoodsPage extends StatefulWidget {\n\nconst AllCategoryGoodsPage({key, required this.category}) : super(key: key);\n\nfinal CategoryData category;\n\n@override\nState<AllCategoryGoodsPage> createState() => _AllCategoryGoodsPageState();\n\n}\n\nclass _AllCategoryGoodsPageState extends State<AllCategoryGoodsPage> {\n\n@override\nvoid initState() {\n super.initState();\n Provider.of<AllGoodsViewModel>(context, listen: false).fetchAllItems(id: widget.category.id);\n}\n\n@override\nWidget build(BuildContext context) {\n\n final model = Provider.of<AllGoodsViewModel>(context);\n\n return MaterialApp(\n   home: Scaffold(\n     appBar: AppBar(),\n     body: Container(\n         width: MediaQuery.of(context).size.width,\n         height: MediaQuery.of(context).size.height,\n         color: Colors.white,\n         child: GridView.builder(\n             shrinkWrap: true,\n             physics: BouncingScrollPhysics(),\n             gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(\n                 crossAxisCount: 2,\n                 childAspectRatio: 0.76),\n             itemCount: model.goods.length,\n             itemBuilder: (context, index) {\n               return ViewGoods(model: model.goods[index], index: index);\n             }),\n     ),\n   ),\n );\n}\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

查看商品

\n
class _ViewGoodsState extends State<ViewGoods> {\n\n  GlobalKey _key = GlobalKey();\n\n  @override\n  void initState() {\n    super.initState();\n    WidgetsBinding.instance.addPostFrameCallback((_){\n      Provider.of<AllGoodsViewModel>(context, listen: false).setting(widget.model);\n    });\n  }\n\n  @override\n  Widget build(BuildContext context) {\n\n    final model = Provider.of<AllGoodsViewModel>(context);\n    final size = MediaQuery.of(context).size;\n\n    Widget inCart(){\n      return Container(\n        key: _key,\n        height: 31,\n        child: GestureDetector(\n          onPanDown: (details) {\n            Goods? item = widget.model;\n            RenderBox _cardBox = _key.currentContext!.findRenderObject() as RenderBox;\n            final localPosition = details.localPosition;\n            final localDx = localPosition.dx;\n            if (localDx <= _cardBox.size.width/2) {\n              Goods value = cart.firstWhere((element) => element.id == item.id);\n              if (item.optState == 0 ? value.orderCount <= 1 : value.orderCount <= value.opt!.count) {\n                setState(() {\n                  context.read<AllGoodsViewModel>().setCountInCart(0);\n                  final ind = cart.indexWhere((element) => element.id == item.id);\n                  if (ind != -1) {\n                    cart[ind].orderCount = 0;\n                    SQFliteService.cart.delete(cart[ind].id);\n                    cart.removeAt(ind);\n                    NotificationCenter().notify("cart");\n                  }\n                });\n              } else {\n                model.haveItem(item: item, operation: item.optState == 0 ? -1 : (-1 * value.opt!.count));\n              }\n            } else {\n              model.haveItem(item: item, operation: item.optState == 0 ? 1 : item.count);\n            }\n\n          },\n          child: TextButton(\n            style: ButtonStyle(\n                backgroundColor: MaterialStateProperty.all(Design.appColor),\n                padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 8, horizontal: 10)),\n                shape: MaterialStateProperty.all(RoundedRectangleBorder(\n                  borderRadius: BorderRadius.circular(10.0),\n                ))\n            ),\n            onPressed: (){},\n            child: Container(\n              child: RichText(\n                text:  TextSpan(\n                  text: "",\n                  children:[\n                    WidgetSpan(\n                      alignment: PlaceholderAlignment.middle,\n                      child: Icon(Icons.remove, size: 14, color: Colors.white),\n                    ),\n                    TextSpan(\n                      text: "  ${widget.model.optState == 0 ? (widget.model.minPrice ?? widget.model.price) : widget.model.opt!.price} \xe2\x82\xbd  ",\n                      style: TextStyle(\n                          color: Colors.white,\n                          fontSize: 14,\n                          fontWeight: FontWeight.w500,\n                          fontFamily: "Inter"\n                      ),\n                    ),\n                    WidgetSpan(\n                      alignment: PlaceholderAlignment.middle,\n                      child: Icon(Icons.add, size: 14, color: Colors.white),\n                    )\n                  ],\n                ),\n              ),\n            ),\n          ),\n        ),// Your TextButton code goes here.\n      );\n    }\n\n    Widget noInCart(){\n      return Container(\n        key: _key,\n        height: 31,\n        child: TextButton(\n          style: ButtonStyle(\n              backgroundColor: MaterialStateProperty.all(model.orderBg),\n              padding: MaterialStateProperty.all(EdgeInsets.symmetric(vertical: 8, horizontal: 10)),\n              shape: MaterialStateProperty.all(RoundedRectangleBorder(\n                borderRadius: BorderRadius.circular(10.0),\n              ))\n          ),\n          onPressed: (){\n            Goods? item = widget.model;\n            model.haveItem(item: item, operation: item.optState == 0 ? 1 : item.count);\n          },\n          child: Container(\n            child: RichText(\n              text:  TextSpan(\n                text: "${widget.model.optState == 0 ? widget.model.minPrice == null ? widget.model.price : widget.model.minPrice : widget.model.opt!.price} \xe2\x82\xbd ",\n                style: TextStyle(\n                    color: widget.model.minPrice != null ? Design.grey : Colors.black,\n                    decoration: widget.model.optState == 0 && widget.model.minPrice != null ? TextDecoration.lineThrough : TextDecoration.none,\n                    fontSize: 14,\n                    fontWeight: FontWeight.w500,\n                    fontFamily: "Inter"\n\n                ),\n                children:[\n                  TextSpan(\n                    text: widget.model.minPrice == null ? "" : " ${widget.model.price} \xe2\x82\xbd",\n                    style: TextStyle(\n                        color: Colors.black,\n                        decoration: TextDecoration.none,\n                        fontSize: 14,\n                        fontWeight: FontWeight.w500,\n                        fontFamily: "Inter"\n                    ),\n                  ),\n\n                  WidgetSpan(\n                    alignment: PlaceholderAlignment.middle,\n                    child: Icon(Icons.add, size: 14, color: Colors.black),\n                    style: TextStyle(\n                      color: Colors.black,\n                      decoration: TextDecoration.none,\n                    ),\n                  )\n                ],\n              ),\n            ),\n          ),\n        ),\n      );\n    }\n\n\n    Widget card({required Size size}) {\n      return Container(\n        color: Colors.white,\n        width: (size.width/2.4) - 11,\n        margin: EdgeInsets.only(right: (widget.index.isOdd ? 16 : 5) , left: (widget.index.isOdd ? 5 : 16)),\n        child: Column(\n          children: [\n            Stack(\n                children: [\n                  Container(\n                    height: (size.width/2 - 16),\n                    width: (size.width/2),\n                    padding:  EdgeInsets.all(1),\n                    decoration: BoxDecoration(\n                      image: DecorationImage(\n                          fit: BoxFit.cover,\n                          image: NetworkImage(widget.model.images.first)\n                      ),\n                      borderRadius: BorderRadius.all(Radius.circular(10.0)),\n                      border: Border.all(\n                          width: 1,\n                          color: Design.lightGrey\n                      ),\n                    ),\n                  ),\n                  Visibility(\n                    visible: model.countInCart == 0 ? false : true,\n                    child: Container(\n                      height: (size.width/2 - 16),\n                      width: (size.width/2),\n                      decoration: BoxDecoration(\n                        color: Colors.black.withOpacity(0.5),\n                        borderRadius: BorderRadius.all(Radius.circular(10.0)),\n                      ),\n                      child: Visibility(\n                        visible: true,\n                        child: Center(\n                          child: model.orderCountText,\n                        ),\n                      ),\n                    ),\n                  )\n                ]\n            ),\n            SizedBox(height: 5),\n            Align(\n              alignment: Alignment.centerLeft,\n              child: Container(\n                height: 34.h,\n                child: Text(widget.model.name,\n                  maxLines: 2,\n                  style: TextStyle(\n                    fontSize: 14.sp,\n                    fontWeight: FontWeight.w500,\n                    fontFamily: "Inter",\n                  ),\n                ),\n              ),\n            ),\n            SizedBox(height: 5),\n            Align(\n                alignment: Alignment.centerLeft,\n                child: (context.read<AllGoodsViewModel>().countInCart == 0) ? noInCart() : inCart()\n            )\n          ],\n        ),\n      );\n    }\n\n    return card(size: size);\n  }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

和视图模型

\n
class AllGoodsViewModel extends ChangeNotifier {\n\n  List<Goods> goods = List.empty(growable: true);\n  late DocumentSnapshot documentSnapshot;\n\n  Future<void> fetchAllItems({required String id}) async {\n    final data = await FirestoreService.shared.fetchItems(id);\n    this.goods = [];\n    sortGoods(data);\n  }\n\n  Future<void> paginateAllGoods({required String id}) async {\n    var data = await FirestoreService.shared.fetchRequestItems(documentSnapshot: documentSnapshot, id: id);\n    sortGoods(data);\n  }\n\n  Future<void> sortGoods(Tuple? data) async {\n    if (data != null) {\n      if (data.data.length == 0) {\n        return;\n      }\n      this.documentSnapshot = data.id;\n      final items = data.data as List<QueryDocumentSnapshot<Map<String, dynamic>>>;\n      this.goods.addAll(items.map((e) => Goods.fromFirestoreTo(e)).toList());\n      notifyListeners();\n    }\n  }\n\n\n  var _countInCart = 0;\n  int get countInCart => _countInCart;\n\n  var _orderBg = Design.lightGrey;\n  Color get orderBg => _orderBg;\n\n  var _orderColor = Design.paleWhite;\n  Color get orderColor => _orderColor;\n\n  var _orderStyle;\n  TextStyle get orderStyle => _orderStyle;\n\n  var _orderCountText = Text("0");\n  Text get orderCountText => _orderCountText;\n\n  void setting(Goods item) {\n\n    final ind = cart.indexWhere((element) => element.id == item.id);\n    if (ind != -1) {\n      item.optState = cart[ind].isOpt ? 1 : 0;\n      // chooseView.configure(item: item, tag: order.tag)\n      setReadyData(index: ind);\n    } else {\n      //chooseView.configure(item: item, tag: 0)\n      setCountInCart(0);\n    }\n  }\n\n  // add and remove product\n  void haveItem({required Goods item, required int operation}) async {\n    final ind = cart.indexWhere((element) => element.id == item.id);\n    if (ind == -1) {\n      final minCount = item.optState == 0 ? 1 : item.opt!.count;\n      if (item.count < minCount) {\n        //order.shake();\n      } else {\n        cart.add(item);\n        final ind = cart.length - 1;\n        cart.last.isOpt = item.optState == 0 ? false : true;\n        cart.last.orderCount = minCount;\n        await SQFliteService.cart.addToCart(cart.last);\n        // animate();\n        NotificationCenter().notify("cart");\n        changeCountInCart(operation);\n        countText(index: ind, item: cart.last);\n        orderText();\n      }\n    } else {\n      final count = cart[ind].orderCount;\n      if (count <= item.count) {} else { return; } //order.shake()\n      if (operation < 0 || count + operation <= item.count) {} else { return; } //order.shake()\n      cart[ind].orderCount += operation;\n      SQFliteService.cart.updateItem(cart[ind].id, {"orderCount":cart[ind].orderCount});\n      NotificationCenter().notify("cart");\n      changeCountInCart(operation);\n      countText(index: ind, item: cart[ind]);\n    }\n  }\n\n\n  // when re-displaying a product\n  void setReadyData({required int index}) {\n    final empty = cart[index].orderCount == 0;\n    empty ? defaultOrderText() : orderText();\n    if (empty) { return; }\n    setCountInCart(cart[index].orderCount);\n    countText(item: cart[index]);\n  }\n\n  //quantity of goods in the basket\n  void countText({int? index, required Goods item}) {\n    var ind = index;\n    if (index == null) {\n      ind = cart.indexWhere((element) => element.id == item.id);\n    }\n    if (ind == -1) { return; }\n    if (cart[ind!].orderCount >= item.count){\n      final text = Text.rich(\n        TextSpan(\n          style: TextStyle(\n            fontSize: 22,\n            fontFamily: "Inter",\n            fontWeight: FontWeight.w400,\n            color: Colors.white,\n          ),\n          text: "$_countInCart",\n          children: <TextSpan>[\n            TextSpan(text: "\\n\xd0\x9d\xd0\xb5\xd1\x82 \xd0\xb2 \xd0\xbd\xd0\xb0\xd0\xbb\xd0\xb8\xd1\x87\xd0\xb8\xd0\xb8", style: TextStyle(\n                fontSize: 16,\n                fontFamily: "Inter",\n                fontWeight: FontWeight.bold,\n                color: Colors.white\n            )),\n          ],\n        ),\n        textAlign: TextAlign.center,\n      );\n      changeOrderCountText(text);\n    } else {\n      final text = Text("$_countInCart",\n        style: TextStyle(\n            fontSize: 22,\n            fontFamily: "Inter",\n            fontWeight: FontWeight.w400,\n            color: Colors.white\n        ),\n      );\n      changeOrderCountText(text);\n    }\n\n  }\n\n  void changeOrderCountText(Text widget){\n    _orderCountText = widget;\n  }\n\n  void defaultOrderColor(){\n      _orderColor = Design.paleWhite;\n      _orderStyle = TextStyle(color: Design.dark);\n  }\n\n  // add button text\n  void orderText() {\n    _orderColor = Design.paleWhite;\n    _orderStyle = TextStyle(color: Colors.white, fontWeight: FontWeight.w500, fontSize: 14);\n    if (_orderBg == Design.paleWhite) {\n      _orderBg = Design.appColor;\n    }\n  }\n\n  void defaultOrderText() {\n    _orderBg = Design.paleWhite;\n    _orderColor = Design.dark;\n    _orderStyle = TextStyle(color: Colors.white, fontWeight: FontWeight.w700, fontSize: 14);\n  }\n\n  void setCountInCart(int value){\n    _countInCart = value;\n    notifyListeners();\n  }\n\n  void changeCountInCart(int value){\n    _countInCart += value;\n    notifyListeners();\n  }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

整个问题是,当您通过单击按钮进行更改时,所有产品的数量都会发生变化

\n

在此输入图像描述\n在此输入图像描述\n在此输入图像描述

\n

小智 2

我认为问题出在 AllGoodsViewModel() 的 ChangeNotifierProvider 上:

ChangeNotifierProvider(
    create: (context) => AllGoodsViewModel(),
),
Run Code Online (Sandbox Code Playgroud)

因为你使用它,并且在任何地方用上下文调用它,它都会返回相同的模型,这就是为什么每个产品都显示相同的计数。

我建议您通过将每个小部件包装在产品列表中来使用 ChangeNotifierProvider.value():

ChangeNotifierProvider.value(
  value: MyModel(),
  child: ...
)
Run Code Online (Sandbox Code Playgroud)

而且您不需要在全球范围内提供您的模型。