iOS 16 自动旋转失败

Dee*_*rma 6 uiviewcontroller uikit ios swift ios16

我在 iOS 16 上发现了一个奇怪的自动旋转问题,这在其他 iOS 版本中没有出现过。更糟糕的是,如果我将设备连接到 XCode 并进行调试,则不会出现该问题。仅当我通过触摸应用程序图标直接在设备上启动应用程序时才能看到它,这就是我无法识别任何修复的原因。我所做的是在应用程序启动时禁用自动旋转(通过仅返回 .landscape supportedInterfaceOrientations),然后在 0.2 秒后不久,我强制自动旋转到设备的当前界面方向(使用self.setNeedsUpdateOfSupportedInterfaceOrientations)。但是,如果通过触摸应用程序图标直接启动应用程序(而不是从调试器启动),则自动旋转会失败!

这是完整重现该问题的示例代码。运行应用程序时,请确保 iPhone 处于纵向模式。该函数viewWillTransition(to size:, with coordinator:)不会被调用,并且所有子视图不会自动旋转。请建议我一个解决方法!

import UIKit

class ViewController: UIViewController {

 public var windowOrientation: UIInterfaceOrientation {
     return view.window?.windowScene?.interfaceOrientation ?? .unknown
 }

  private var disableAutoRotation = true

  override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    
     var orientations:UIInterfaceOrientationMask = .landscapeRight
    
      if !self.disableAutoRotation {
         orientations = .all
      }
   
       return orientations
    }


 override func viewDidLoad() {
     super.viewDidLoad()
    // Do any additional setup after loading the view.
    
      self.view.backgroundColor = UIColor.systemGreen
    
     DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
         self.autoRotateNotification()
     })
 }

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    
    super.viewWillTransition(to: size, with: coordinator)

    let orientation = windowOrientation

        
    coordinator.animate(alongsideTransition: {_ in
    
    }, completion: { [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in
        
        let orient = self.windowOrientation
        
        if orient.isLandscape {
            self.view.backgroundColor = UIColor.systemGreen
        } else {
            self.view.backgroundColor = UIColor.systemOrange
        }
       
    })
}

func autoRotateNotification() {
  
   DispatchQueue.main.asyncAfter(deadline: .now(), execute: {
     
       /*
        * HELP::: This code does something only when debug directly from XCode,
        * not when directly launching the app on device!!!!
        */

       self.disableAutoRotation = false

       if #available(iOS 16.0, *) {
           UIView.performWithoutAnimation {
               self.setNeedsUpdateOfSupportedInterfaceOrientations()
           }
          
       } else {
           // Fallback on earlier versions
          UIViewController.attemptRotationToDeviceOrientation()
       }
   })
}


 }
Run Code Online (Sandbox Code Playgroud)

编辑:有人提到移动 autorotateNotification 来viewDidAppear解决问题,但事实并非如此。如前所述,如果应用程序通过 XCode 调试器启动,则没有问题。仅当通过触摸应用程序图标直接启动应用程序时才会出现此问题!这是也失败的每个人参考的示例代码。

 import UIKit

 class ViewController: UIViewController {


   public var windowOrientation: UIInterfaceOrientation {
       return view.window?.windowScene?.interfaceOrientation ?? .unknown
   }

    private var disableAutoRotation = true

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
    
       var orientations:UIInterfaceOrientationMask = .landscapeRight
    
     if !self.disableAutoRotation {
         orientations = .all
     }
   
      return orientations
   }

   override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
      return .landscapeLeft
   }

   private var autoRotated = false

   override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    if !autoRotated {
        autoRotated = true
        
        self.autoRotateNotification()     
    }
}


override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    
    super.viewWillTransition(to: size, with: coordinator)
    
    coordinator.animate(alongsideTransition: {_ in
    
    }, completion: { [unowned self] (UIViewControllerTransitionCoordinatorContext) -> Void in
        let orient = self.windowOrientation
        
        if orient.isLandscape {
            self.view.backgroundColor = UIColor.systemGreen
        } else {
            self.view.backgroundColor = UIColor.systemOrange
        }
       
    })
}


func autoRotateNotification() {
  
    self.disableAutoRotation = false

    if #available(iOS 16.0, *) {
        self.setNeedsUpdateOfSupportedInterfaceOrientations()
    } else {
        // Fallback on earlier versions
        UIViewController.attemptRotationToDeviceOrientation()
    }
 }


 }
Run Code Online (Sandbox Code Playgroud)

小智 -1

viewWillTransition似乎没有被调用,因为您的函数autoRotateNotification()是从viewDidLoad视图在屏幕上仍然不可见的函数调用的。

尝试将代码移至 中viewDidAppear,viewWillTransition 将被调用。

这是我的工作代码:

class ViewController: UIViewController {
    
    var forceLandscape: Bool = false
    
    override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        forceLandscape ? .landscape : .all
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        forceLandscape = true
        UIView.performWithoutAnimation {
            setNeedsUpdateOfSupportedInterfaceOrientations()
        }
    }
    
    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)
        print("viewWillTransition")
    }
}
Run Code Online (Sandbox Code Playgroud)