info.plist 中支持的界面方向似乎阻止了对 shouldAutorotate 的调用

Supported Interface Orientations in info.plist seem to block calls to shouldAutorotate

我正在设计一个 iPad/iPhone 应用程序,其中的界面设计为横向和纵向看起来一样好,我希望界面在启动时以一个方向优雅地显示其他。同时,我需要能够在不同时间进行 enable/disable 自转。我想我知道如何做这两件事,但它们似乎不能很好地结合在一起。

我可以在 Xcode 项目中设置允许的设备方向,这似乎在项目 info.plist 中创建了几个数组项:"Supported interface orientations (iPad)" 和 "Supported interface orientations (iPhone)"其中列出了每种设备的允许方向。这些项目的存在使得从启动屏幕到各个方向的转换都像丝绸一样顺畅。

我可以 enable/disable 通过覆盖我的根视图控制器中的 shouldAutorotate 来自动旋转(目前只有一个控制器)。问题是 info.plist 中支持的接口项的存在似乎抑制了对 shouldAutorotate 的所有调用,从而使自动旋转控制无效。

class   RootController: UIViewController
  {
    var allowAutorotation = true    //  My autorotation switch.
      { didSet    { guard   allowAutorotation   else  { return }
                    UIViewController.attemptRotationToDeviceOrientation()
                    /*  Do other stuff.   */ }   }

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask
      { NSLog ("RootController: supportedInterfaceOrientations")
        return .allButUpsideDown  }

    override var shouldAutorotate: Bool
      { NSLog ("RootController: shouldAutorotate")
        return allowAutorotation  }

    override func viewDidLoad()
      { allowAutorotation = true
        super.viewDidLoad()  }

         }

我正在使用 viewDidLoad 尽早调用 attemptRotationToDeviceOrientation()。如果我不这样做,即使设备处于横向,应用程序屏幕也会显示为纵向。 (对于 Portrait 显示正确,但 Portrait 不正确。)我尝试从其他地方进行类似的调用,包括应用程序委托中的 didFinishLaunchingWithOptions,我认为这可能是最合乎逻辑的地方,但它没有似乎没什么区别。

如果我从 info.plist 中删除 Supported Orientation 项,并在代码中定义允许的方向,如图所示,我可以从我的 NSLog 指示器中看到调用 shouldAutorotate 确实在适当的时刻发生,但启动看起来在景观中有点尴尬。在启动屏幕中,状态栏的方向是错误的:沿着垂直边缘之一而不是顶部,并且当过渡到应用程序屏幕时,它通常会以倾斜约 10-20° 的水平方向逐渐消失。它立即捕捉到水平(它是如此之快,事实上,有时很难看到),然后状态栏正确地在顶部,从那一刻起一切看起来都很好,但效果似乎有点不专业。

因为它只是暂时发生,并且只在启动时发生一次,我想我可以接受它(我不能没有自动旋转控制)但我希望有人可以建议一种方法来让 shouldAutorotate 调用工作即使在 info.plist 中定义了方向。或者其他策略?

我想我有解决这些问题的方法。为了消除启动屏幕淡出时的异常旋转动画,我使用 CATransactions 禁用隐式动画,直到应用程序首次激活:

class RootController: UIViewController  {

private var appIsLaunching = true  //  Set false when app first becomes active. Never set true again.

func appDidBecomeActive()
  { if appIsLaunching  { appIsLaunching = false; CATransaction.setDisableActions (false) } } 

override func viewWillTransition (to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
  { if appIsLaunching  { CATransaction.setDisableActions (true) } 
    super.viewWillTransition (to: size, with: coordinator) }

        }

并且在 appDelegate 中:

func applicationDidBecomeActive ( _ application: UIApplication )
  { let root = window!.rootViewController as! RootController; root.appDidBecomeActive() }

我相信这是可行的,因为默认的 CATransaction 始终有效,即使没有显式事务也是如此。从启动屏幕到第一个视图的交叉溶解似乎很完美。

启动屏幕中的状态栏仍然出现在错误的方向。我得出的结论是,最好在项目设置中或通过设置 Status bar is initially hidden in info.plist 将其关闭。不理想,但可以接受。