跳转至正文

自适应应用的一般方法

如何让 Flutter 应用具备自适应能力的一般建议。

那么,究竟 如何 将面向常规移动设备设计的应用,做得在多种设备上都出色?需要哪些步骤?

有大型应用实战经验的 Google 工程师推荐以下三步法。

步骤 1:抽象

#

Step 1: Abstract info common to any UI widget

首先,确定计划做成动态的 widget。分析这些 widget 的构造函数,抽象出可共享的数据。

常见需要自适应的 widget 包括:

  • Dialogs, both fullscreen and modal

  • Navigation UI, both rail and bottom bar

  • Custom layout, such as "is the UI area taller or wider?"

  • 对话框,全屏与模态

  • 导航 UI,rail 与底部栏

  • 自定义布局,例如「UI 区域更高还是更宽?」

例如,在 Dialog widget 中,可共享包含对话框 内容 的信息。

或者,应用窗口较小时用 NavigationBar,较大时用 NavigationRail。这些 widget 可能共享可导航目的地列表。此时可创建 Destination widget 保存该信息,并指定 Destination 同时包含图标与文本标签。

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

步骤 2:测量

#

Step 2: How to measure screen size

有两种方式确定显示区域尺寸:MediaQueryLayoutBuilder

MediaQuery

#

MediaQuery

#

过去你可能用 MediaQuery.of 判断设备屏幕尺寸。但如今设备屏幕尺寸与形状多样,该判断可能误导。

例如,应用可能只占大屏上的小窗口。若用 MediaQuery.of 得出屏幕很小(实则大屏上的小窗口),且应用锁定竖屏,会导致应用窗口锁定在屏幕中央并带黑边,在大屏上绝非理想 UI。

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

测量屏幕空间有两种方式:根据你需要整个应用窗口尺寸还是更局部的尺寸,使用 MediaQuery.sizeOfLayoutBuilder

若希望 widget 全屏显示(即使应用窗口很小),请用 MediaQuery.sizeOf,以便根据应用窗口尺寸选择 UI。上一节中,你希望基于整个应用窗口决定尺寸行为,因此应使用 MediaQuery.sizeOf

build 方法内请求应用窗口尺寸(如 MediaQuery.sizeOf(context))会在 size 属性变化时使该 BuildContext 重建。

LayoutBuilder

#

LayoutBuilder

#

LayoutBuilderMediaQuery.sizeOf 目标类似,但有区别。

LayoutBuilder 不提供应用窗口尺寸,而提供父 Widget 的布局约束。即根据你在 widget 树中添加 LayoutBuilder 的位置获取尺寸信息。此外,LayoutBuilder 返回 BoxConstraints 而非 Size,因此给出内容有效的宽高范围(最小与最大),而非固定尺寸,这对自定义 widget 很有用。

例如,自定义 widget 希望尺寸基于分配给该 widget 的空间,而非整个应用窗口,此时请用 LayoutBuilder

步骤 3:分支

#

Step 3: Branch the code based on the desired UI

此时,你必须决定在选择显示哪版 UI 时使用哪些尺寸断点。例如,Material layout 指南建议窗口宽度小于 600 逻辑像素时使用底部导航栏,600 像素及以上使用导航 rail。再次强调,选择不应依赖设备 类型,而应依赖设备可用窗口尺寸。

要了解在 NavigationRailNavigationBar 之间切换的示例,请参阅 Building an animated responsive app layout with Material 3 Codelab。

下一页讨论如何确保应用在大屏与折叠屏上表现最佳。