跳转至正文

大屏设备

将应用适配大屏时需注意的事项。

本页提供优化应用以改善其在大屏上行为的指导。

Flutter 与 Android 一样,将大屏定义为平板、折叠屏以及运行 Android 的 ChromeOS 设备。Flutter 将 Web、桌面与 iPad 视为大屏设备。

使用 GridView 布局

#

请看以下应用截图。应用在 ListView 中显示 UI。左图为移动设备上的运行效果,右图为应用在大屏设备上运行、且 尚未应用本页建议 时的效果。

Sample of large screen

这并不理想。

Android 大屏应用质量指南iOS 对应指南 均指出,文字与方框都不应占满全屏宽度。如何以自适应方式解决?

常见方案是使用 GridView,如下一节所示。

GridView

#

GridView

#

可用 GridView widget 将现有 ListView 转为尺寸更合理的项。

GridViewListView widget 类似,但不仅能线性排列 widget 列表,还能在二维数组中排列 widget。

GridView 也有与 ListView 类似的构造函数。ListView 默认构造函数对应 GridView.countListView.builder 类似 GridView.builder

GridView 还有用于更自定义布局的额外构造函数。更多信息请访问 GridView API 页面。

例如,若原应用使用 ListView.builder,可换成 GridView.builder。若项很多,建议使用 builder 构造函数仅构建实际可见的项 widget。

两个 widget 的构造函数参数大多相同,替换较直接。但需确定 gridDelegate 的设置。

Flutter 提供强大的预制 gridDelegates,可供使用,即:

SliverGridDelegateWithFixedCrossAxisCount

Lets you assign a specific number of columns to your grid.

SliverGridDelegateWithMaxCrossAxisExtent

Lets you define a max item width.

SliverGridDelegateWithFixedCrossAxisCount :为网格指定固定列数。

SliverGridDelegateWithMaxCrossAxisExtent :定义项的最大宽度。

其他方案

#

另一种方式是使用 BoxConstraintsmaxWidth 属性,涉及:

  • Wrap the GridViewin a ConstrainedBox and give it a BoxConstraints with a maximum width set.

  • Use a Container instead of a ConstrainedBox if you want other functionality like setting the background color.

  • ConstrainedBox 包裹 GridView,并设置带最大宽度的 BoxConstraints

  • 若需设置背景色等其他功能,可用 Container 替代 ConstrainedBox

选择最大宽度时,可考虑 Material 3 在 Applying layout 指南中的推荐值。

折叠屏

#

如前所述,Android 与 Flutter 设计指南均建议锁定屏幕方向,但部分应用仍会锁定。请注意,在折叠屏上运行可能导致问题。

折叠屏折叠时应用可能正常,展开后可能出现 letterboxing(信箱模式)。

SafeArea & MediaQuery 页所述,letterboxing 指应用窗口锁定在屏幕中央,周围为黑边。

为何会这样?

在使用 MediaQuery 确定应用窗口尺寸时可能发生。设备折叠时方向被限制为竖屏。底层 setPreferredOrientations 使 Android 使用竖屏兼容模式,应用以 letterboxed 状态显示。此状态下 MediaQuery 永远收不到允许 UI 扩展的更大窗口尺寸。

有两种解决方式:

  • Support all orientations.

  • Use the dimensions of the physical display. In fact, this is one of the few situations where you would use the physical display dimensions and not the window dimensions.

  • 支持所有方向。

  • 使用 物理显示 的尺寸。事实上,这是 少数 应使用物理显示尺寸而非窗口尺寸的情况之一。

如何获取物理屏幕尺寸?

可使用 Display API,其中包含物理设备的尺寸、像素比与刷新率。

以下示例代码获取 Display 对象:

dart
/// AppState object.
ui.FlutterView? _view;

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  _view = View.maybeOf(context);
}

void didChangeMetrics() {
  final ui.Display? display = _view?.display;
}

重要的是找到你所关心 view 的 display。这形成面向未来的 API,应能处理当前 未来的多显示与多 view 设备。

自适应输入

#

支持更多屏幕也意味着扩展输入控件。

Android 指南描述了大屏格式设备支持的三个层级。

3 tiers of large format device support

第三层为最低支持级别,包括鼠标与触控笔输入(Material 3 指南Apple 指南)。

若应用使用 Material 3 及其按钮与选择器,则已内置对各种额外输入状态的支持。

若有自定义 widget?请参阅 User input 页了解如何添加 widget 输入支持

#

在多种不同尺寸设备上工作时,导航可能带来独特挑战。通常应根据可用屏幕空间在 BottomNavigationBarNavigationRail 之间切换。

更多信息(及对应示例代码)请参阅文章 Developing Flutter apps for Large screens 中的 Problem: Navigation rail 一节。