【问题标题】:Any way to have strongly typed use of Navigator?有什么方法可以强类型地使用 Navigator?
【发布时间】:2021-05-22 16:05:22
【问题描述】:

我有一个 MaterialButton 和以下 onPressed 字段:

onPressed: () async {
    final int intResult = await showMyDialog(context, provider.myArg) ?? 0;
    //...
}

这是showMyDialog函数:

Future<int?> showMyDialog(BuildContext context, Object someArg) async {
  return showDialog<int>(
    context: context,
    builder: (BuildContext context) {
      return ChangeNotifierProvider<MyProvider>(
        create: (_) => MyProvider(someArg),
        child: MyDialog(),
      );
    },
  );
}

现在我看到的问题是,在MyDialogStatelessWidget)中,我需要使用Navigator.pop(...) 来为等待的intResult 返回一个值。但是,我似乎无法找到对这些调用进行强类型化的方法,因此很难确定不会发生运行时类型错误。

我现在最好的方法是继承 StatelessWidget 并将 Navigator 函数包装在其中:

abstract class TypedStatelessWidget<T extends Object> extends StatelessWidget {
  void pop(BuildContext context, [T? result]) {
    Navigator.pop(context, result);
  }
}

那么在TypedStatelessWidget&lt;int&gt;中我们可以正常使用pop(context, 0),而pop(context, 'hi')会被编辑器标记为类型错误。这仍然没有链接对话框返回类型和导航器,但至少它避免了手动键入每个导航器调用。


有没有更好的方法来进行强类型化?

【问题讨论】:

    标签: flutter dart strong-typing flutter-navigation


    【解决方案1】:

    您无需包装 Navigator.pop 方法,因为您可以键入它的返回值。

    Navigator.pop<int>(context, 1);
    

    我让你参考pop method documentation了解更多详情。

    【讨论】:

    • 这个问题是即使你使用Navigator.pop&lt;int&gt;,如果你使用showDialog&lt;bool&gt;,你在编辑时不会出错。所以在pop 上打字基本上是没有意义的。
    • 您将无法通过使用 showDialog 获得此类错误。您不妨从头开始重新编码 showDialog 以使用您的 TypedStatelessWidget 类,以便构建器属性期望返回 TypedStatelessWidget.
    • 好吧,如果这确实是唯一的方法,我不妨试试。我仍然想知道为什么人们应该接受打字之间的这种差距;听起来更像是一种 javascript/pythonic 方式来执行您只相信对话框类型与导航值匹配的事情。
    【解决方案2】:

    所以这就是我最终要做的。本质上,这允许将小部件类型和提供者类型“捆绑在一起”。这样,当在对话框中调用自定义 pop 函数时,有一个类型协定(请参阅 PopType)返回值应该是什么。使用WillPopScope 还支持非手动弹出导航,它获取类型化提供程序的返回函数和参数(请参阅TypedProvider 中的抽象函数)以将该值正确传递到小部件树。

    mixin TypedWidget<T, N extends TypedProvider<T>?> on Widget {
      ChangeNotifierProvider<N> asTypedWidget(
          BuildContext context, N Function(BuildContext) createProviderFunc) {
        return ChangeNotifierProvider<N>(
            create: createProviderFunc,
            builder: (BuildContext innerContext, _) {
              return WillPopScope(
                  child: this,
                  onWillPop: () {
                    final N provider = Provider.of<N>(innerContext, listen: false);
                    if (provider == null) {
                      return Future<bool>.value(true);
                    }
                    provider.onPopFunction(provider.getPopFunctionArgs());
                    return Future<bool>.value(true);
                  });
            });
      }
    
      /// Builds this TypedWidget inside `showDialog`.
      ///
      /// The `TypedProvider`'s `onPopFunction` is called if the
      /// dialog is closed outside of a manual `Navigator.pop()`. This doesn't have
      /// a return type; all returning actions should be done inside the defined
      /// `onPopFunction` of the provider.
      ///
      /// Example:
      /// ```
      /// MyTypedWidget().showTypedDialog(
      ///   context,
      ///   (BuildContext context) => MyTypedProvider(...)
      /// );
      /// ```
      Future<void> showTypedDialog(
          BuildContext context, N Function(BuildContext) createProviderFunc,
          {bool barrierDismissible = true}) async {
        await showDialog<void>(
          context: context,
          barrierDismissible: barrierDismissible,
          builder: (_) => asTypedWidget(context, createProviderFunc),
        );
      }
    }
    
    abstract class TypedProvider<PopType> with ChangeNotifier {
      TypedProvider(this.onPopFunction);
    
      Function(PopType) onPopFunction;
      PopType getPopFunctionArgs();
    
      void pop(BuildContext context) {
        onPopFunction(getPopFunctionArgs());
        Navigator.pop(context);
      }
    }
    

    很可能还有其他方法可以实现这一点,而且这个解决方案当然有一些限制,但它有效地为对话框提供了强类型。

    【讨论】:

      猜你喜欢
      • 2021-06-05
      • 2015-12-29
      • 2015-04-20
      • 2016-10-27
      • 2015-01-28
      • 2014-05-15
      • 2014-05-24
      • 2022-11-06
      • 2015-08-22
      相关资源
      最近更新 更多