我将我的 App 里用的 Flutter 升级到了 3.19,没想到,以前我用 showDialog 和 AlertDialog 组合创建的二次确认框,变得无敌难看了,大幅度增加了整个框的圆角和里面默认按钮的圆角。不得已,我必须修改一下,以保持样式的美观。
此前,我使用的 showDialog,里面创建的 AlertDialog,这些默认都是 Material 风格的。不过,我此前试过,在 iOS 上的视觉表现也不错,虽然跟苹果的系统级弹框不太像,但是可以接受。
这次 Flutter 大改,导致这个弹框难看到炸裂,我想到的只能是苹果的换成苹果风格,那样至少看起来不是太奇怪。
然后我发现了有三个函数,showDialog,showCupertinoDialog,showAdaptiveDialog,我首先实验了,仍然使用 showDialog,但是里面 builder 返回的 Widget,我换成了 CupertinoAlertDialog,我发现,竟然毫无违和性。
我不禁好奇,那么 showCupertinoDialog 到底提供了什么独特的功能呢?在 sdk 里还看到了 showAdaptiveDialog,那么这个又是干什么?我发现 showAdaptiveDialog 只是按照 Platform 的取值,自动决定调用 showDialog 和 showCupertinoDialog。
那么问题就来了,showCupertinoDialog 到底有什么独特之处?实测就是大部分是一样的,只是有一些视觉上的细微差异,也有一点交互上的细微差异。如果你不是特别仔细认真的人,可能不会注意到。
不过这种仍然破坏了交互和视觉的一致性,对于设计师来说,往往是很辣眼睛的。
showCupertinoDialog 区别就在于,第一,弹出的模态对话框,其遮罩颜色是比较浅的,不像 Material 风格下,遮罩颜色较深,这个不对比着看,还不容易发现。
第二,弹出的模态框,在 Material 风格下,点击空白区域,可以直接取消掉模态框。但是在 Cupertino 风格下,不允许取消,必须显示点击"取消"按钮。这是交互上的一个小小的差异,不过这是苹果内在交互一致性的体验。
可惜,这些东西,如果你不去查文档,是很难了解到的,就算去查了文档,也不是很容易就掌握到这些差异的,至少我自己是没从文档看出来,而是从网友的分享里看出来的。
下面这种写法是我结合文档和网友的分享推理出来的,实测是没问题的。
dart
void showCustomDialog(BuildContext context) {
showAdaptiveDialog(
context: context,
builder: (BuildContext context) {
// 检查运行平台
if (Platform.isIOS) {
// 使用 CupertinoAlertDialog
return CupertinoAlertDialog(
title: Text("iOS Alert"),
content: Text("This is an iOS-style alert dialog."),
actions: <Widget>[
CupertinoDialogAction(
child: Text("Cancel"),
onPressed: () => Navigator.of(context).pop(),
),
CupertinoDialogAction(
child: Text("OK"),
onPressed: () => Navigator.of(context).pop(),
),
],
);
} else {
// 使用 AlertDialog
return AlertDialog(
title: Text("Android Alert"),
content: Text("This is an Android-style alert dialog."),
actions: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("Cancel"),
),
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("OK"),
),
],
);
}
},
);
}
结论
用 showDialog 还是用 showCupertinoDialog 都是可以的。或者图省事,就用 showAdaptiveDialog。在 builder 里,用什么 Dialog 决定了出现后的样式,比如 AlertDialog 和 CupertinoAlertDialog 长得就不一样。不过无论外面用什么函数来调用,里面的都可以随意组合的。只是考虑到系统的交互规范和视觉一致,一般不会混用。
推荐使用 showAdaptiveDialog,里面则根据 Platform.isIOS 等来决定是返回 CupertinoAlertDialog 和是返回 AlertDialog。用错了不会报错的,可以工作,只是丑。