基于 Flutter 官方文档(Flutter 3.44)整理,总结目前 Flutter 官方推荐的多端适配方案,并结合实际项目经验给出最佳实践。
前言
随着 Flutter 已经覆盖 Android、iOS、Web、Windows、macOS、Linux 等多个平台,一个应用早已不再只运行在手机上。
如今,我们需要面对越来越多的设备:
- 手机
- 平板
- 折叠屏
- ChromeOS
- Desktop
- Web
- 超宽屏显示器
很多 Flutter 开发者仍然停留在:
dart
if (Platform.isAndroid) {}
if (width > 600) {}
事实上,这已经不是 Flutter 官方推荐的方案。
Flutter 官方最新文档提出了一个核心思想:
不要关注设备(Device),而要关注窗口(Window)。
这也是 Flutter Adaptive Design 的核心。
本文将结合官方文档,完整介绍 Flutter 当前推荐的自适应设计方案。
什么是 Responsive?什么是 Adaptive?
官方给出了非常容易理解的一句话:
Responsive 是让 UI 适应空间(Fit the space)。
Adaptive 是让 UI 适用于空间(Usable in the space)。 (Flutter 文档)
很多文章都会把两者混为一谈,其实区别很明显。
Responsive(响应式)
Responsive 关注的是:
空间变化以后,UI 如何重新排列。
例如:
手机
+---------+
List
List
List
平板
+---------+---------+
Menu Content
布局发生改变,但是业务逻辑完全一致。
典型做法:
- GridView 修改列数
- Row / Column 切换
- 宽度变化
- Padding 调整
Adaptive(自适应)
Adaptive 更关注:
不同平台应该提供不同的交互体验。
例如:
手机:
- BottomNavigationBar
平板:
- NavigationRail
桌面:
- NavigationDrawer
虽然都是导航,但不同设备最适合的导航方式完全不同。(Flutter 文档)
理想状态
官方建议:
一个优秀的 Flutter App 应该既是 Responsive,又是 Adaptive。(Flutter 文档)
Flutter 官方推荐的三步法(Three Steps)
Flutter 官方专门提出了一套适配流程。
整个 Adaptive UI 可以总结成三步。
Abstract
↓
Measure
↓
Branch
这也是官方最推荐的设计方式。(Flutter 文档)
第一步:Abstract(抽象)
官方建议:
不要直接写两个页面。
而是先把公共数据抽离出来。
例如导航。
不要这样:
dart
if (isTablet)
NavigationRail(...)
else
NavigationBar(...)
应该先抽象:
dart
class Destination {
final IconData icon;
final String label;
}
然后:
dart
NavigationRail(
destinations: ...
)
NavigationBar(
destinations: ...
)
这样:
- UI 不同
- 数据一致
- 逻辑一致
后续维护成本最低。(Flutter 文档)
第二步:Measure(测量)
很多 Flutter 项目都会这样写:
dart
MediaQuery.of(context).size.width
虽然没有问题。
但是官方已经推荐使用新的 API。
✅推荐
dart
MediaQuery.sizeOf(context)
而不是:
dart
MediaQuery.of(context)
原因:
MediaQuery.of() 会监听整个 MediaQuery。
而:
MediaQuery.sizeOf(context)
只监听 Size。
重建范围更小,性能更好。(Flutter 文档)
LayoutBuilder
另一种官方推荐方式:
dart
LayoutBuilder(
builder: (context, constraints) {
return ...
},
)
为什么?
因为它拿到的是:
BoxConstraints
而不是整个 Window。
例如:
Screen
├──── LeftPanel
└──── RightPanel
如果 RightPanel 只有 400dp。
使用:
MediaQuery
得到的是整个窗口。
使用:
LayoutBuilder
得到的是:
400dp
对于组件开发更加准确。(Flutter 文档)
第三步:Branch(分支)
最后一步就是:
根据空间决定 UI。
例如:
dart
if (width < 600)
使用:BottomNavigationBar
else
否则:NavigationRail
官方特别强调:
不要根据设备判断。
不要写:
dart
if (Platform.isAndroid)
也不要:
dart
if (tablet)
应该根据:
Window Size
来判断。(Flutter 文档)
SafeArea 与 MediaQuery
SafeArea 是 Flutter 最经典的适配组件。
dart
SafeArea(
child: ...
)
作用:
自动避开:
- 刘海
- 挖孔
- 状态栏
- Home Indicator
- 圆角
官方建议:
一般把 Scaffold 的 body 包裹在 SafeArea 中,而不是包裹整个 Scaffold。(Flutter 文档)
不要锁定横竖屏
官方明确建议:
不要锁死 Portrait。
原因包括:
- 平板支持多窗口
- 折叠屏窗口尺寸不断变化
- Desktop 可以自由拉伸
- Web 可以调整浏览器窗口
如果锁定方向,将大幅增加未来适配成本。(Flutter 文档)
不要根据 Orientation 切布局
很多项目:
dart
OrientationBuilder(
或者:
dart
MediaQuery.orientation
官方建议:
不要。
因为:
Landscape 不代表空间更大。
例如:
折叠屏:
Landscape
┌────┬────┐
│App │Chat│
└────┴────┘
虽然横屏。
但 App 实际宽度可能只有 350dp。
真正应该判断的是:
MediaQuery.sizeOf(context)
或者:
LayoutBuilder
而不是 Orientation。(Flutter 文档)
不要检测设备类型
官方再次强调:
不要判断:
- isPhone
- isTablet
- isDesktop
因为:
今天:
Tablet
明天:
Tablet Split Screen
后天:
Desktop Window
设备类型无法准确代表可用空间。
应该始终基于窗口尺寸进行布局决策。(Flutter 文档)
自动的平台适配
Flutter 已经帮我们完成了很多平台差异。
例如:
- 页面切换动画
- 滚动物理效果
- Overscroll
- 图标
- Haptic Feedback
- Text Selection
- TextField 行为
例如:
Android:
Glow
iOS:
Bounce
开发者无需额外处理,大部分情况下 Flutter 会自动选择符合平台习惯的行为。(Flutter 文档)
官方最佳实践总结
结合官方文档,可以总结出以下几条建议:
✅ 根据窗口尺寸,而不是设备类型进行布局。
✅ 使用 MediaQuery.sizeOf() 获取窗口大小。
✅ 自定义组件优先使用 LayoutBuilder。
✅ 将公共数据抽象出来,让不同布局共享业务逻辑。
✅ 使用 SafeArea 处理刘海屏和系统安全区域。
✅ 不要锁定横竖屏,兼容多窗口与折叠屏。
✅ 不要依赖 OrientationBuilder 或设备方向决定整体布局。
✅ 充分利用 Flutter 已提供的平台自适应能力。
一个推荐的项目结构
对于大型 Flutter 项目,可以建立统一的响应式入口,例如:
lib/
├── adaptive/
│ ├── breakpoints.dart
│ ├── adaptive_layout.dart
│ ├── adaptive_navigation.dart
│ └── adaptive_dialog.dart
│
├── features/
│
└── shared/
其中:
- breakpoints.dart:统一定义断点。
- adaptive_layout.dart:负责根据窗口尺寸切换布局。
- adaptive_navigation.dart:封装 BottomNavigationBar、NavigationRail、Drawer 等导航形式。
- adaptive_dialog.dart:统一管理对话框样式。
这种方式与官方提出的 Abstract → Measure → Branch 思路高度一致,能够让整个项目的适配策略更加统一。
总结
Flutter 的自适应设计理念正在逐渐从「适配手机和平板」演进为真正意义上的「多端统一开发」。
相比过去关注设备类型,官方现在更强调:
- 关注窗口,而不是设备。
- 关注可用空间,而不是屏幕尺寸。
- 关注用户体验,而不是平台判断。
牢记官方提出的三步法:
Abstract → Measure → Branch
配合 MediaQuery.sizeOf()、LayoutBuilder、SafeArea 等工具,就可以构建一套可维护、可扩展且适用于手机、平板、折叠屏、桌面以及 Web 的 Flutter 自适应架构。
参考资料
- Flutter 官方文档:《Adaptive and responsive design》 (Flutter 文档)
- Google I/O 2024:《How to build Adaptive UI with Flutter》 (youtube.com)