iOS16+ 横向显示 UIViewController 仅适用于单屏无法工作 [Swift 5.7]

Che*_*ati 9 xcode swift ios16 xcode14 swift5.7

在 iOS 16 之前,横向呈现单屏对于纵向应用来说是可以的。工作代码如下。

备注整个应用程序仅处于纵向模式。

override public var shouldAutorotate: Bool {
    return false
}

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscapeLeft
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeLeft
}
Run Code Online (Sandbox Code Playgroud)

我找到了解决方案,但它适用于UIWindowScene,但我需要 UIWindow 中的解决方案。我需要帮助来修复 iOS 16 中的问题。

Xcode - 14.0,iOS - 16.0,模拟器 - 14 Pro

如果有人需要,我可以准备演示。

小智 5

这可以通过两种方式完成。

1.我个人比较喜欢这种方式

1.1 将此函数保留在AppDelegate中来处理方向(这是必须的)

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    return .all
}
Run Code Online (Sandbox Code Playgroud)

1.2 您想要在哪个 ViewController 中施加力方向,转到该视图控制器并在变量声明部分添加这些行

var forceLandscape: Bool = false

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
           forceLandscape ? .landscape : .portrait
}
Run Code Online (Sandbox Code Playgroud)

我们将更新forceLandscape,以便它得到更新,然后supportedInterfaceOrientations也将得到更新

1.3 这里我们设置更新forceLandscape的触发器(我们可以在按钮操作中添加这些代码行以处理IOS 16强制旋转)

if #available(iOS 16.0, *) {
            self.forceLandscape = true
            guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else { return }
            self.setNeedsUpdateOfSupportedInterfaceOrientations()
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
                windowScene.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeRight)){
                        error in
                        print(error)
                        print(windowScene.effectiveGeometry)
                }
            })
Run Code Online (Sandbox Code Playgroud)

这将更新forceLandscape,因此它将检查方向并根据它进行更新

上面的代码行是一种方法,下面给出另一种方法

2. 另一种方法是更新 AppDelegate 类中的方向:

2.1 在AppDelegate中保留这个函数和属性来处理方向(这是必须的)

var orientation : UIInterfaceOrientationMask = .portrait
        func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
            return orientation
        }
Run Code Online (Sandbox Code Playgroud)

2.2 在viewcontroller按钮动作中我们可以更新属性

@IBAction func buttonAction(_ sender: Any) {
        let appDel = UIApplication.shared.delegate as! AppDelegate
        appDel.orientation = .landscape

        if #available(iOS 16.0, *) {
            DispatchQueue.main.async {
                let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene
                self.setNeedsUpdateOfSupportedInterfaceOrientations()
                self.navigationController?.setNeedsUpdateOfSupportedInterfaceOrientations()
                windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .landscape)) { error in
                    print(error)
                    print(windowScene?.effectiveGeometry ?? "")
                }
            }
        }else{
            UIDevice.current.setValue(UIInterfaceOrientation.landscapeLeft.rawValue, forKey: "orientation")
        }
Run Code Online (Sandbox Code Playgroud)

  • 知道如何让它适用于使用 swiftUI 制作的一个特定屏幕吗? (5认同)

Che*_*ati 2

经过多次尝试,我想出了一个简单的解决方案。正如我在问题中提到的,我的整个应用程序仅处于纵向模式,并且我只想以横向方式呈现一个屏幕。

此代码不需要任何外部窗口makeKeyAndVisible 如果你使用额外的窗口来呈现,那么你需要为 iOS 16 单独编写关闭。

在 iOS 16 之前版本中运行的旧代码将保持不变,不会发生任何变化。

魔线如下。

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if let _ = window?.rootViewController?.presentedViewController as? LandscapeChartVC {
        if #available(iOS 16.0, *) {
            return .landscapeLeft
        } else {
            return .portrait
        }
    } else {
        return .portrait
    }
}
Run Code Online (Sandbox Code Playgroud)

我已经在 appDelegate 的supportedInterfaceOrientationsFor.

那么你可以改变单词presentedViewController来获取你的控制器。就是这样。

添加对 iPad 的所有 3 或 4 方向的支持:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if UIDevice.IS_IPAD {
        return .allButUpsideDown
    } else {
        if let _ = window?.rootViewController?.presentedViewController as? LandscapeChartVC {
            if #available(iOS 16.0, *) {
                return .landscapeLeft
            } else {
                return .portrait
            }
        } else {
            return .portrait
        }
    }
Run Code Online (Sandbox Code Playgroud)

如果需要 iPad 应用程序锁定方向,您可以遵循 iPhone/以上代码。

这个想法给出了答案,并感谢所有分享兴趣的人。如果有人仍然得到更多改进的解决方案,我会很乐意更新。