1mindmap 2 root((Flutter 屏幕旋转适配)) 3 原理 4 旋转手机 = 窗口尺寸变了 5 Flutter 检测到 → 自动重新布局 6 怎么监听 7 OrientationBuilder 根据横竖屏切布局 8 MediaQuery.sizeOf 根据宽度切布局 更推荐 9 怎么锁定屏幕 10 SystemChrome.setPreferredOrientations 11 锁定竖屏 portraitUp 12 锁定横屏 landscapeLeft Right 13 恢复自动 DeviceOrientation.values 14 安卓 vs iOS 15 Android 一行代码搞定 16 iOS 要多配置 3 层 17 Info.plist 声明支持方向 18 AppDelegate 写回调动态控制 19 ViewController 也会参与判断 20 视频全屏实战 21 进全屏 → 切横屏 22 退出全屏 → 切回竖屏 23 iOS 需要额外在 AppDelegate 里配合 24
在移动开发中,屏幕旋转是非常常见的场景。
例如:
- 视频播放器全屏播放
- 平板横屏适配
- 表单页面横竖屏切换
- 折叠屏展开与收起
Flutter 已提供了完整的横竖屏支持。
本文将从实际开发角度介绍:
- 如何监听屏幕旋转
- 如何适配横竖屏布局
- 如何锁定横屏或竖屏
- Android 与 iOS 的区别,尤其是 iOS 特别要注意的地方
什么是屏幕旋转
当用户旋转手机时:
1设备方向变化 2 ↓ 3系统更新窗口尺寸 4 ↓ 5Flutter 重新布局 6 ↓ 7Widget 重新构建 8
因此:
Flutter 屏幕旋转本质上是窗口尺寸变化后的重新布局过程。
使用 OrientationBuilder 监听方向变化
Flutter 官方推荐使用:
1OrientationBuilder(builder: (context, orientation) { 2 return orientation == Orientation.portrait ? const PortraitPage() 3 : const LandscapePage(); 4 }, 5); 6
效果:
- 竖屏显示 PortraitPage
- 横屏显示 LandscapePage
实现横竖屏不同布局
例如商品列表页面:
竖屏:
12列 Grid 2
横屏:
13列 Grid 2
代码:
1OrientationBuilder(builder: (context, orientation) { 2 return GridView.count(rossAxisCount: orientation == Orientation.portrait ? 2 : 3); 3 }, 4); 5
使用 MediaQuery 获取方向
除了 OrientationBuilder。
还可以直接获取方向:
1final orientation = MediaQuery.orientationOf(context); 2
判断:
1if (orientation == Orientation.landscape) { 2 print('横屏'); 3} 4
使用 MediaQuery 获取屏幕尺寸
实际开发中更推荐:
1final size = MediaQuery.sizeOf(context); 2
例如:
1final width = MediaQuery.sizeOf(context).width; 2
根据宽度决定布局:
1if (width > 600) { 2 return TabletPage(); 3} 4 5return MobilePage(); 6
相比 Orientation。
这种方式更适合:
- 平板
- 折叠屏
- 多窗口
场景。
OrientationBuilder 和 MediaQuery 的区别
| 方式 | 作用 |
|---|---|
| OrientationBuilder | 根据方向切换布局 |
| MediaQuery.orientationOf | 获取当前方向 |
| MediaQuery.sizeOf | 获取屏幕尺寸(推荐) |
Flutter 官方建议:
1优先根据 Size 设计布局 2而不是只依赖 Orientation 3
因为大屏设备和折叠屏场景下:
1方向不变 2 3尺寸也可能变化 4
锁定竖屏
很多 App 会禁止横屏。
实现方式:
1void main() async { 2 WidgetsFlutterBinding.ensureInitialized(); 3 4 await SystemChrome.setPreferredOrientations([ 5 DeviceOrientation.portraitUp, 6 ]); 7 8 runApp(const MyApp()); 9} 10
锁定横屏
例如:
- 视频播放器
- 游戏
- 车机应用
代码:
1await SystemChrome.setPreferredOrientations([ 2 DeviceOrientation.landscapeLeft, 3 DeviceOrientation.landscapeRight, 4]); 5
恢复自动旋转
1await SystemChrome.setPreferredOrientations( 2 DeviceOrientation.values, 3); 4
恢复系统默认行为。
Android 与 iOS 的区别
为什么
1SystemChrome.setPreferredOrientations(...) 2
Android 可以正常工作。
但 iOS 经常不生效
原因是Android 和 iOS 的方向管理机制完全不同
Android
Android 中:
1SystemChrome.setPreferredOrientations(...) 2
Flutter 最终会调用 Android 原生:
1Activity.setRequestedOrientation() 2
请求系统切换方向。App一般能够正确旋转方向
因此大多数 Flutter 项目不需要编写 Android 原生代码 只使用 Flutter API 即可。
iOS
iOS 不一样。 很多人以为:
1SystemChrome.setPreferredOrientations(...) 2
就能直接控制方向。
实际上 Flutter 只是向系统提出请求
最终是否旋转由 UIKit 决定
Apple 官方文档也说明:
系统会综合判断:
- App 支持哪些方向
- 当前 ViewController 支持哪些方向
- 当前 Window 支持哪些方向
来判断当前是否允许旋转。
iOS 配置 Info.plist
如果需要用户旋转手机屏幕 首页保持竖屏, 需要在 Info.plist 配置 Portrait
1<key>UISupportedInterfaceOrientations</key> 2<array> 3 <string>UIInterfaceOrientationPortrait</string> 4</array> 5
表示整个 App 默认只支持竖屏
那视频播放器为什么还能横屏
在 AppDelegate 实现如下回调: 例如:
1override func application( 2 _ application: UIApplication, 3 supportedInterfaceOrientationsFor window: UIWindow? 4) -> UIInterfaceOrientationMask { 5 return OrientationUtils.shared.orientationLock 6} 7
作用: 动态控制当前页面允许的方向
例如:
1首页 2↓ 3Portrait 4 5视频页 6↓ 7Landscape 8 9退出视频页, 返回其他页面 10↓ 11Portrait 12
Apple 官方说明:
如果实现了这个方法。 系统会优先询问使用这里返回的方向,而不仅仅使用 Info.plist。
Flutter + iOS 常见方案
Info.plist
默认:
1Portrait 2
AppDelegate
动态控制:
1var orientationLock: 2UIInterfaceOrientationMask = .portrait 3
进入视频页:
1orientationLock = .landscape 2
退出视频页:
1orientationLock = .portrait 2
然后 Flutter 调用:
1SystemChrome.setPreferredOrientations(...) 2
完成横竖屏切换。
Android iOS 横竖屏切换总结
Android:
1Flutter 请求方向 2 3系统通常直接执行 4
iOS:
1Flutter 请求方向 2 ↓ 3Info.plist 判断 4 ↓ 5AppDelegate 判断(如果实现,覆盖Info.plist中条件) 6 ↓ 7ViewController 判断(和AppDelegate/Info.plist取交集) 8 ↓ 9UIKit 最终决定(交集结果) 10
因此:
- Android 通常只需要 Flutter 代码;
- iOS 除了 Flutter 代码外,还需要正确配置 Info.plist,还要通过
AppDelegate动态控制横竖屏。
视频播放器横屏实战
进入全屏:
1await SystemChrome 2 .setPreferredOrientations([ 3 DeviceOrientation.landscapeLeft, 4 DeviceOrientation.landscapeRight, 5]); 6
退出全屏:
1await SystemChrome 2 .setPreferredOrientations([ 3 DeviceOrientation.portraitUp, 4]); 5
这是最常见的使用场景。
《Flutter 屏幕旋转适配》 是转载文章,点击查看原文。