那么,你究竟是如何将一款为传统移动设备设计的应用,使其在各种设备上都美观大方?需要哪些步骤?

谷歌工程师们,在大型应用中拥有这方面丰富的经验,推荐以下三步法。

步骤 1:抽象化

#

Step 1: Abstract info common to any UI widget

首先,识别你计划动态化的组件 (widget)。分析这些组件的构造函数,并抽象出可以共享的数据。

需要自适应的常见组件有

  • 对话框,包括全屏和模态对话框
  • 导航 UI,包括导航侧边栏和底部导航栏
  • 自定义布局,例如“UI 区域是更高还是更宽?”

例如,在一个 Dialog 组件中,你可以共享包含对话框内容的那个信息。

或者,你可能希望在应用窗口较小时切换使用 NavigationBar,而在应用窗口较大时使用 NavigationRail。这些组件很可能会共享一个可导航目的地的列表。在这种情况下,你可以创建一个 Destination 组件来保存这些信息,并指定 Destination 既包含图标也包含文本标签。

接下来,你将评估屏幕尺寸,以决定如何显示你的 UI。

步骤 2:测量

#

Step 2: How to measure screen size

你有两种方法来确定显示区域的大小:MediaQueryLayoutBuilder

MediaQuery

#

过去,你可能使用 MediaQuery.of 来确定设备的屏幕尺寸。然而,如今的设备屏幕尺寸和形状多种多样,这种测试可能会产生误导。

例如,你的应用可能目前在一个大屏幕上占据一个小窗口。如果你使用 MediaQuery.of 方法并得出屏幕很小的结论(而实际上,应用是在大屏幕上的一个小窗口中显示),并且你锁定了应用的竖屏模式,这会导致应用窗口锁定在屏幕中央,周围是黑色。这在大屏幕上绝不是一个理想的 UI。

请记住,MediaQuery.sizeOf 返回的是应用整个屏幕的当前尺寸,而不仅仅是单个组件的尺寸。

你有两种方法来测量你的屏幕空间。你可以使用 MediaQuery.sizeOfLayoutBuilder,具体取决于你是想获取整个应用窗口的大小,还是更局部的尺寸。

如果你的组件希望全屏显示,即使在应用窗口很小的情况下,也可以使用 MediaQuery.sizeOf,这样你就可以根据应用窗口本身的尺寸来选择 UI。在上一节中,你希望根据整个应用窗口来确定尺寸行为,因此会使用 MediaQuery.sizeOf

build 方法内部请求应用窗口尺寸,例如 MediaQuery.sizeOf(context),会导致给定的 BuildContextsize 属性发生任何变化时进行重建。

LayoutBuilder

#

LayoutBuilder 实现了与 MediaQuery.sizeOf 类似的目标,但有一些区别。

LayoutBuilder 不提供应用窗口的大小,而是提供来自父 Widget 的布局约束。这意味着你将根据在组件树中添加 LayoutBuilder 的特定位置获取尺寸信息。此外,LayoutBuilder 返回的是一个 BoxConstraints 对象,而不是 Size 对象,因此你将获得内容的有效宽度和高度范围(最小值和最大值),而不仅仅是一个固定尺寸。这对于自定义组件非常有用。

例如,设想一个自定义组件,你希望其尺寸基于专门分配给该组件的空间,而不是整个应用窗口。在这种情况下,请使用 LayoutBuilder

步骤 3:分支

#

Step 3: Branch the code based on the desired UI

此时,你必须决定在选择要显示的 UI 版本时使用哪些尺寸断点。例如,Material 布局指南建议,对于宽度小于 600 逻辑像素的窗口,使用底部导航栏;对于宽度等于或大于 600 像素的窗口,使用导航侧边栏。同样,你的选择不应取决于设备的类型,而应取决于设备可用的窗口大小。

要查看 NavigationRailNavigationBar 之间切换的示例,请查阅使用 Material 3 构建动画自适应应用布局

下一页将讨论如何确保你的应用在大屏幕和可折叠设备上呈现最佳效果。