Flutter中iPad使用SystemChrome.setPreferredOrientations失效问题求助
iPad 单页面锁定横屏的解决方案
问题出在iPad的多场景(Scene)机制上,默认情况下Flutter的SystemChrome.setPreferredOrientations无法覆盖iOS原生Scene的方向设置,导致iPad上不生效。以下是无需修改全局info.plist的解决方法:
步骤1:iOS原生端(SceneDelegate.swift)修改
在iOS项目的SceneDelegate.swift中,通过MethodChannel接收Flutter传递的方向锁定指令,动态修改当前场景的支持方向:
import UIKit import Flutter class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? // 存储当前允许的屏幕方向,默认支持所有方向 private var allowedOrientations: UIInterfaceOrientationMask = .all func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } let window = UIWindow(windowScene: windowScene) let flutterEngine = FlutterEngine(name: "lockOrientationEngine") flutterEngine.run() GeneratedPluginRegistrant.register(with: flutterEngine) // 初始化MethodChannel let channel = FlutterMethodChannel(name: "com.example/orientation", binaryMessenger: flutterEngine.binaryMessenger) channel.setMethodCallHandler { [weak self] call, result in switch call.method { case "setLandscapeOnly": self?.allowedOrientations = .landscape // 强制刷新当前场景的方向设置 windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: self?.allowedOrientations ?? .all)) result(nil) case "restoreAllOrientations": self?.allowedOrientations = .all windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: self?.allowedOrientations ?? .all)) result(nil) default: result(FlutterMethodNotImplemented) } } let flutterViewController = FlutterViewController(engine: flutterEngine, nibName: nil, bundle: nil) window.rootViewController = flutterViewController self.window = window window.makeKeyAndVisible() } // 重写此方法,返回当前允许的屏幕方向 func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return allowedOrientations } }
步骤2:Flutter端代码调整
在需要锁定横屏的页面中,结合SystemChrome和MethodChannel,同时通知Flutter层和原生层修改方向:
import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; class LandscapeLockedPage extends StatefulWidget { const LandscapeLockedPage({super.key}); @override State<LandscapeLockedPage> createState() => _LandscapeLockedPageState(); } class _LandscapeLockedPageState extends State<LandscapeLockedPage> { final MethodChannel _orientationChannel = const MethodChannel('com.example/orientation'); @override void initState() { super.initState(); // 通知原生锁定横屏 _orientationChannel.invokeMethod('setLandscapeOnly'); // 设置Flutter层面的方向限制 SystemChrome.setPreferredOrientations([ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); } @override void dispose() { // 通知原生恢复所有方向 _orientationChannel.invokeMethod('restoreAllOrientations'); // 恢复Flutter层面的方向支持 SystemChrome.setPreferredOrientations([ DeviceOrientation.portraitUp, DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('横屏锁定页面')), body: const Center(child: Text('仅横屏显示')), ); } }
关键说明
- iPad的Scene机制会独立管理每个窗口的方向规则,必须通过原生SceneDelegate动态修改
supportedInterfaceOrientations才能生效。 - MethodChannel用于Flutter与原生的状态同步,确保页面切换时两端的方向设置一致。
- 无需修改
info.plist的全局方向配置,只要info.plist中UISupportedInterfaceOrientations已包含你需要的方向(默认配置一般都满足)即可。
内容的提问来源于stack exchange,提问作者csacchetti
相关产品推荐
相关产品推荐

