问题描述
我有一个带有以下 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(),);
},);
}
现在我看到的问题是在 MyDialog
(a StatelessWidget
) 中,我需要使用 Navigator.pop(...)
为等待的 intResult
返回一个值。但是,我似乎无法找到一种方法来强类型这些调用,因此很难确定不会发生运行时类型错误。
我现在最好的方法是继承 StatelessWidget
并将 Navigator
函数包装在其中:
abstract class TypedStatelessWidget<T extends Object> extends StatelessWidget {
void pop(BuildContext context,[T? result]) {
Navigator.pop(context,result);
}
}
然后在TypedStatelessWidget<int>
中我们可以正常使用pop(context,0)
,而pop(context,'hi')
会被编辑器标记为类型错误。这仍然没有链接对话框返回类型和导航器,但至少它避免了手动输入每个导航器调用。
有没有更好的方法来实现这种强类型?
解决方法
您无需包装 Navigator.pop
方法,因为您可以键入其返回值。
Navigator.pop<int>(context,1);
我让您参考 pop method documentation 了解更多详情。
,所以这就是我最终要做的。本质上,这允许将小部件类型和提供程序类型“绑定在一起”。这样,当在对话框中调用自定义 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);
}
}
很可能还有其他方法可以实现这一点,这个解决方案当然有一些限制,但它有效地为对话框提供了强类型。