You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:36:11