首页 > 解决方案 > 如何在连接器中连接多个模型(ScopedModel)

问题描述

我正在尝试将水果项目添加到购物车,但没有任何反应

一旦我按下“添加水果”按钮,什么都没有发生。它应该在购物车列表中添加水果项目。按下“添加水果”按钮后,尝试通过按应用栏中的购物车图标来访问购物车屏幕时出现错误。

在此处输入图像描述

这种方式不能正常工作:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new ScopedModel(
      model: ListModel(),
      child: ScopedModel(
        model: CartModel(),
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'State Management Scoped Model',
          theme: myAppTheme,
          initialRoute: '/',
          routes: {
            '/': (context) => MyList(),
            '/cart': (context) => MyCart(),
          },
        ),
      ),
    );
  }
}

还有一种方法:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new ScopedModel<ListModel>(
      model: ListModel(),
      child: ScopedModelDescendant<ListModel>(
        builder: (context, child, model) => ScopedModel<CartModel>(
          model: CartModel(),
        ),
        child: MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'State Management Scoped Model',
          theme: myAppTheme,
          initialRoute: '/',
          routes: {
            '/': (context) => MyList(),
            '/cart': (context) => MyCart(),
          },
        ),
      ),
    );
  }
}

在此处输入图像描述

使用 Provider 包一切正常:)

标签: flutterdart

解决方案


还不能评论。

尝试将 MaterialApp 添加为 ScopedModel 的直接后代子级,并在对模型的更改实际影响 UI 时使用 ScopedModelDescendant。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new ScopedModel<ListModel>(
      model: ListModel(),
      child: MaterialApp(
         debugShowCheckedModeBanner: false,
         title: 'State Management Scoped Model',
         theme: myAppTheme,
         initialRoute: '/',
         routes: {
           '/': (context) => MyList(),
           '/cart': (context) => MyCart(),
         },
       ),
    );
  }
}

当属性发生变化时,可以在列出卡片项目时在 MyCart 小部件中说

... widget tree ...

child: ScopedModelDescendant<ListModel>(
         builder: (context, child, ScopedModel<CartModel> model){
           List cartItems = model.cartItems;
           List<Widget> cartItemWidgets=[];
           cartItems.forEach((cartItemData){
             cartItemWidgets.add(new CartItemWidget(cartItemData));
           });
           return Column(
             children:cartItemWidgets,
           );
         }
       ),

...widget tree...

希望这可以帮助。

注意,每次调用 notifyLsteners() 时,ScopedModelDescendant 都会发生变化。我认为在整个应用程序上这样做会非常昂贵。

编辑:

忘记添加rebuildOnChange: true 属性。而且还犯了错误。

... widget tree ...
//__YOUR__MODEL__: model that changes 
child: ScopedModelDescendant<__YOUR__MODEL__>(
         rebuildOnChange: true, // now the widget rebuilds when notifyListeners(); is called inside the __YOUR__MODEL__
         builder: (context, child,__YOUR__MODEL__ model){
           List cartItems = model.cartItems;
           List<Widget> cartItemWidgets=[];
           cartItems.forEach((cartItemData){
             cartItemWidgets.add(new CartItemWidget(cartItemData));
           });
           return Column(
             children:cartItemWidgets,
           );
         }
       ),

...widget tree...

编辑2:

通过浏览 git 存储库,我能够构建一个您想要做的示例。这是GitHub 存储库的链接。注意:我已向您发起所有权转让。如果您选择接受,我会更新链接。但也要描述实现。

您想要有两个模型 ListModel 和 CartModel,列表模型当前用作实际列表的占位符。

在 CartModel 中,您附加了 ListModel。

每当您需要该列表时,您都可以通过 CartModel 获得它。

我是如何改变的?

  1. 将 Fruit 类拆分为一个单独的文件。// 对象.dart

  2. 将ListModel 变成了扩展 Model 的抽象 ShoppingModel

  3. 创建了一个使用 ShoppingModel 和 CartModel 扩展 Model 的单例 SuperModel。给它一个私有构造函数和一个实例属性。这个对象永远只有一个实例。SuperModel 是一个混合模型,它能够访问 ShoppingModel 和 CartModel 的所有公共属性。为了避免编辑器显示错误,添加了一个文件//analysis_options.yaml 来抑制错误。请注意,这不会影响程序,您可以在网上找到有关它的更多信息。

  4. CartModel 扩展了 ShoppingModel,现在 CartModel 可以访问 ShoppingModel 的所有方法,而不必存储 ListModel。使用 ShoppingModel 添加您可能必须在多个模型中使用的属性。

  5. 将应用程序包装在 ScopeModel 中,模型属性是 SuperModel。由于 SuperModel 是一个单例,我使用了 SuperModel.instance,它永远不必被实例化。

  6. 在可能发生更改的任何地方都添加了 ScopedModelDescendant,不要忘记 rebuildOnChange: true 属性。

我还给了你存储库的所有者。

一般来说,在使用多个模型时,如果需要交换属性,请使用继承和混合。我总是使用一个顶级抽象模型后代类来保存我所有其他模型使用的所有数据。其他模型扩展了这个类,因此它们能够访问这些属性。

但是由于我们需要在整个应用程序中访问它们的属性,并且抽象模型后代不知道它们的孩子,我们可以在这种情况下创建所有模型的混合超模型。因为我们将永远需要一个实例,所以让它成为一个单例

class SuperModel extend Model with Model1, Model2{

  SuperModel._privateConstructor();

  static final SuperModel _instance = SuperModel._privateConstructor();

  static SuperModel get instance {
    return _instance;
  }

}

现在我们可以将 SuperModel 传递给 ScopedModel。

要启用无错误 mixins,请添加:

analyzer:
  strong-mode: true
  language:
    enableSuperMixins: true

到 pubspec.yaml 文件的末尾

和一个新的根文件 analysis_options.yaml:

analyzer:
  errors: 
    mixin_inherits_from_not_object: ignore

现在这适用于 Visual Studio 代码,我不知道这对于 Android Studio 是否有任何不同的处理


推荐阅读