Flutter 的 showDialog 和 showCupertinoDialog 有什么区别?

发布于:2024-04-25 ⋅ 阅读:(19) ⋅ 点赞:(0)

在这里插入图片描述
在这里插入图片描述

我将我的 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 风格下,不允许取消,必须显示点击“取消”按钮。这是交互上的一个小小的差异,不过这是苹果内在交互一致性的体验。

可惜,这些东西,如果你不去查文档,是很难了解到的,就算去查了文档,也不是很容易就掌握到这些差异的,至少我自己是没从文档看出来,而是从网友的分享里看出来的。

下面这种写法是我结合文档和网友的分享推理出来的,实测是没问题的。

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。用错了不会报错的,可以工作,只是丑。