【问题标题】:iOS16+ Present UIViewController in landscape only for single screen not working [Swift 5.7]iOS16+ 横向呈现 UIViewController 仅适用于单屏不工作 [Swift 5.7]
【发布时间】:2022-09-23 16:03:50
【问题描述】:

在 iOS 16 之前,横向呈现单个屏幕适用于纵向应用程序。工作代码如下。

override public var shouldAutorotate: Bool {
    return false
}

override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    return .landscapeLeft
}

override public var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
    return .landscapeLeft
}

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

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

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

  • 你成功让它为 UIWindowScene 工作了吗?我收到一个错误,请求的方向不受支持
  • @Gutty1 我只使用 UIWindow。很抱歉,我从未尝试过 UIScene。

标签: swift xcode ios16 xcode14 swift5.7


【解决方案1】:

我在 iOS 16 Release Notes 中找到了一些相关的东西。
https://developer.apple.com/documentation/ios-ipados-release-notes/ios-16-release-notes?changes=lat__8_1
UIKit 中有一些弃用:

弃用
[UIViewController shouldAutorotate] 已弃用,不再支持。 [UIViewController attemptRotationToDeviceOrientation] 已被弃用并替换为 [UIViewController setNeedsUpdateOfSupportedInterfaceOrientations]。
解决方法: 依赖 shouldAutorotate 的应用程序应该使用视图控制器supportedInterfaceOrientations 反映他们的偏好。如果支持的方向发生变化,请使用 `-[UIViewController setNeedsUpdateOfSupportedInterface

我想你可能不得不使用setNeedsUpdateOfSupportedInterface.

【讨论】:

  • 这个我已经试过了,还是不行。。。
  • 不,这真的行不通。
【解决方案2】:

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

1.我个人更喜欢这种方式

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

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

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

var forceLandscape: Bool = false

override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
           forceLandscape ? .landscape : .portrait
}

我们将更新力景观所以它会得到更新,然后支持的接口方向也会更新

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)
                }
            })

这将更新力景观, 所以它会检查方向并根据它更新

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

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

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

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

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")
        }

【讨论】:

    【解决方案3】:

    我想出的从横向纵向呈现模态视图控制器的最佳解决方法是结合setNeedsUpdateOfSupportedInterfaceOrientations()requestGeometryUpdate(.iOS(interfaceOrientations: .landscape)) 并允许 AppDelegate 上的界面方向一个新窗口.

    应用委托:

    var allowedOrientation: UIInterfaceOrientationMask = .allButUpsideDown
    
    func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
        return allowedOrientation
    }
    

    横向呈现视图控制器

    var overlayWindow: UIWindow? // New window to present the controller in
    …
    
    func presentModalInLandscape(vc: ViewController) {
        if #available(iOS 16.0, *) {
            let appdelegate = UIApplication.shared.delegate as! AppDelegate
            appDelegate.allowedOrientation = .landscapeRight
    
            if let currentWindowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
                overlayWindow = UIWindow(windowScene: currentWindowScene)
            }
    
            overlayWindow?.windowLevel = UIWindow.Level.alert
            overlayWindow?.rootViewController = livevc
    
            overlayWindow?.makeKeyAndVisible()
            // It's important to do it after the interface has enough time to rotate
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
               self.overlayWindow?.windowScene?.requestGeometryUpdate(.iOS(interfaceOrientations: .landscapeRight))
               vc.setNeedsUpdateOfSupportedInterfaceOrientations()
            }
    
        } else {
            // For iOS 15 it's enough to present it modally
            self.present(vc, animated: true, completion: nil)
        }
    }
    
    

    然后当你想解雇它时,你需要

    
    if #available(iOS 16.0, *) {
        self.overlayWindow?.isHidden = true // Destroy the window
        self.overlayWindow?.windowScene = nil
        self.overlayWindow = nil 
        appDelegate().allowedOrientation = .allButUpsideDown // Reset allowed orientation
        self.setNeedsUpdateOfSupportedInterfaceOrientations() // Set the controller back
    } else {
        self.presentedViewController?.dismiss(animated: true)
    }
    

    它仍然不是 100%,因为视图控制器以横向呈现,然后轻弹回纵向,然后在一秒钟后再次旋转到横向。但是如果没有 UIWindow,它有时会在锁定横向模式之前执行 2 倍。

    【讨论】:

      猜你喜欢
      • 2012-07-28
      • 2014-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多