img

Flutter 旨在运行在各种设备上。而在多个设备上运行就是适应每个设备的怪癖和功能。

我们开发人员需要注意的一种设备怪癖是与我们的应用程序重叠的系统 UI。它可能是状态栏、凹口或底部指示器。

幸运的是,Flutter 支持开箱即用的MediaQuery. 您可以使用 获取状态栏高度MediaQuery.of(context).padding.top,使用MediaQuery.of(context).viewInsets.bottom获取键盘高度等。

不过,MediaQuery本身也有一些瑕疵。例如,它有padding但也有一个viewPadding属性。有时EdgeInsets.zero即使有可见的模糊系统 UI,它们也会返回。

因此,在本文中,我将尝试为澄清问题。

对于本文的其余部分,每当我指的是paddingviewPadding或者viewInsets,它的MediaQuery是我说的。

分类

首先,我们应该将系统晦涩的 UI 分为两类:

部分模糊的用户界面

这些是状态栏、底部指示器。我们应该在我们的应用程序中考虑这些 UI 以创建身临其境的体验。

完全模糊的用户界面

这些通常是键盘。我们应该调整我们的布局以避免出现这些 UI。

img

请注意,当键盘出现时,底部指示器部分从部分变为完全模糊的 UI。

Flutter 如何处理这个:viewInsetsviewPadding

FlutterMediaQuery将它们分为 2 个属性:

viewInsets完全模糊的 UI所需的空间。

viewPadding部分被遮挡的 UI所需的空间。

img

这2个是相互***独立***的。当键盘出现时,viewInsets.bottom从 0 变为 336,但viewPadding.bottom保持在 34,尽管我们可以看到键盘消耗了我们的应用程序占用的底部指示器空间。

因此,考虑上面完全模糊的 UI 消耗部分模糊的 UI 的情况,Flutter 有一个属性可以解释消耗,而它正是padding!

padding→ 将完全遮挡的部分考虑在内后仍被系统 UI 部分遮挡的显示部分。它是这样计算的:

padding= max(0, viewPadding- viewInsets)

img

我们可以看到,viewInsets相当简单,但paddingviewPadding有时可以互换使用,但是有时候这样做是不明智的。

明智地选择填充:何时使用 viewPadding 和 padding

img

布局 1

我们决定我们希望我们的按钮留在键盘后面。

  • 我们需要设置我们的Scaffold.resizeToAvoidBottomInset = false以防止我们Scaffold调整大小。
  • 对于这种情况,我们应该使用,viewPadding因为那时我们的按钮与流程无关,使用padding可能会导致我们的布局跳下来。

布局 2

我们决定我们希望我们的按钮在键盘出现时转换并保持在顶部。

  • 我们需要检查键盘是否可见使用 viewInsets.bottom > 0
  • 对于这种情况,我们应该使用,padding因为 Flutter 会考虑viewInsets并减少padding到 0。我们的按钮将很好地保持在顶部,无需任何进一步检查。

为什么我的 viewPadding / padding / viewInsets 全为零?

我之前说过我们可以检查是否viewInsets.bottom > 0确定键盘是否可见。这只是部分正确。

MediaQuery.of(context).viewInsets在错误的地方打电话,EdgeInsets.zero即使键盘清楚地显示,我们也只会得到。

错误的地方是什么意思?

在颤振,一Widget,平时Scaffold,可以消耗viewPaddingpadding或者viewInsets 和修改MediaQuery,然后传递到它的孩子。

这个想法是,如果父母照顾了被遮挡的 UI,那么孩子就不应该再担心它们了。

img

img

如果ScaffoldAppBar,它将消耗viewPadding.top

如果ScaffoldBottomNavigationBar,它将消耗viewPadding.bottom

如果 Scaffold 有resizeToAvoidBottomInset = true,它会消耗viewInsets.bottom.

所以,如果你想检查键盘知名度,检查它们之外Scaffold,使用一个InheritedWidget传递下来,如果需要的数据。

为 Android Q 做准备:systemGestureInsets

顺便提一下,MediaQuery还有一个名为 的属性systemGestureInsets。这是针对 Android Q 的手势导航。

总结

  • viewPadding 用于部分模糊的 UI
  • viewInsets 用于完全模糊的 UI
  • padding派生自viewPadding并且viewInsets应该仅在必要时使用。
  • 有些Widgets可以使用这些属性并将修改后的属性传递MediaQuery给他们的孩子。