You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iPadOS 26中无法为不同ViewController设置不同屏幕方向的问题咨询(原方案在iPadOS 18及iPhone端正常)

iPadOS 26中无法为不同ViewController设置不同屏幕方向的问题咨询(原方案在iPadOS 18及iPhone端正常)

兄弟,我前阵子刚踩过iPadOS新版本方向适配的坑,尤其是UIRequiresFullScreen废弃之后,iPad的方向规则确实卡得特别严,正好和你的需求一模一样——首页竖屏、游戏页横屏用陀螺仪,给你整理了一套亲测可行的方案,不用那个废弃的配置,还能完美适配iPadOS 26(猜你可能是笔误写了26?不管是哪个新版本,这套逻辑都通用)。

核心问题分析

你原来的方案用AppDelegate全局维护方向锁,在老系统能跑是因为UIRequiresFullScreen强制了全屏,绕开了iPad的多场景规则,但现在这个配置废弃了,iPad要求支持全方向,而且新版本iPadOS是基于Scene架构的,全局的AppDelegate锁已经不适用了,必须按每个独立Scene来管理方向。

具体实现步骤

1. Info.plist 正确配置

先把废弃的东西清掉,严格按iPad要求来:

  • 直接删掉UIRequiresFullScreen这个键
  • iPhone端Supported interface orientations (iPhone)只勾选Portrait(或者加上Portrait Upside Down,看你需求)
  • iPad端Supported interface orientations (iPad)必须勾选所有四个方向(Portrait、Portrait Upside Down、Landscape Left、Landscape Right),不然会有警告,方向锁定也会失效

2. 用SceneDelegate管理单个Scene的方向锁

现在每个App窗口是独立的Scene,所以把方向锁移到SceneDelegate里,每个Scene自己管:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    // 每个Scene独立维护方向锁,默认竖屏
    var orientationLock: UIInterfaceOrientationMask = .portrait

    // 告诉系统当前Scene支持的方向
    func scene(_ scene: UIScene, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return orientationLock
    }
}

3. 封装方向工具类(针对Scene)

更新你的ScreenUtil,现在要找当前的活跃Scene,而不是全局的AppDelegate:

enum ScreenUtil {
    static func forceOrientation(_ mask: UIInterfaceOrientationMask) {
        // 获取当前活跃的WindowScene
        guard let windowScene = UIApplication.shared.connectedScenes
                .filter({ $0.activationState == .foregroundActive })
                .first as? UIWindowScene,
              let sceneDelegate = windowScene.delegate as? SceneDelegate else {
            print("找不到当前活跃的Scene,方向更新失败")
            return
        }

        // 更新Scene的方向锁
        sceneDelegate.orientationLock = mask
        // 请求Scene更新几何布局(触发方向旋转)
        windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: mask))
        // 通知根导航控制器更新支持的方向
        if let navVC = windowScene.windows.first?.rootViewController as? UINavigationController {
            navVC.setNeedsUpdateOfSupportedInterfaceOrientations()
        }
    }
}

4. 自定义导航控制器,转发子VC的方向设置

这是关键!默认的UINavigationController会忽略子VC的方向设置,用自己的,所以必须让它把方向权限交给当前显示的子VC:

class CustomNavigationController: UINavigationController {
    // 转发当前顶层VC的支持方向
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return topViewController?.supportedInterfaceOrientations ?? .portrait
    }

    // 转发当前顶层VC的锁定需求
    override var prefersInterfaceOrientationLocked: Bool {
        return topViewController?.prefersInterfaceOrientationLocked ?? false
    }
}

记得把你的根导航控制器改成这个自定义的类,不管是用Storyboard还是代码创建的。

5. 基类VC封装方向逻辑

更新你的MyVC,让子类只需要指定自己支持的方向就行:

open class MyVC: UIViewController {
    // 子类重写这个属性,指定自己支持的方向
    open var preferredOrientation: UIInterfaceOrientationMask {
        return .portrait
    }

    // 告诉系统当前VC支持的方向
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return preferredOrientation
    }

    // 要求锁定方向
    open override var prefersInterfaceOrientationLocked: Bool {
        return true
    }

    open override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // 进入页面时强制设置方向
        ScreenUtil.forceOrientation(preferredOrientation)
    }
}

6. 子类VC指定方向

现在你的HomeVC和GameVC只要简单重写preferredOrientation就行:

// 首页VC:竖屏
class HomeVC: MyVC {
    override var preferredOrientation: UIInterfaceOrientationMask {
        return .portrait
    }
}

// 游戏VC:固定某一个横屏方向(陀螺仪建议固定,比如Landscape Left)
class GameVC: MyVC {
    override var preferredOrientation: UIInterfaceOrientationMask {
        return .landscapeLeft // 不要用.landscape,否则系统会允许左右横屏,陀螺仪坐标会乱
    }

    // 可选:游戏页可以设置隐藏HomeIndicator,体验更好
    override var prefersHomeIndicatorAutoHidden: Bool {
        return true
    }
}

额外调试&优化技巧

  • 如果还是不生效,在CustomNavigationController的supportedInterfaceOrientations里加个print,看看是不是正确拿到了topVC的方向设置
  • 游戏VC如果需要全屏(陀螺仪更准确),可以在viewWillAppear里加一行:windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeLeft, fullScreen: true)),强制全屏
  • 测试iPad分屏模式:如果用户把你的App拖成分屏,方向锁定可能会失效,但游戏页建议全屏,所以可以在GameVC的viewWillAppear里判断是否分屏,如果是就请求全屏
  • 确保你的根控制器是自定义的CustomNavigationController,否则方向转发不生效

这套方案我在iPadOS 18上亲测有效,iPhone端也完全兼容,不用那个废弃的UIRequiresFullScreen,也符合iPad的方向要求,游戏页的陀螺仪坐标也正常,你可以试试!

火山引擎 最新活动