如何使用swiftlocking主视图的纵向方向

我使用swift为iPhone创build了一个应用程序,该应用程序由embedded在导航控制器中的许多视图组成。 我想将主视图locking到纵向,只有导航控制器的子视图locking在横向。 这里是我的意思的一个例子:

  • UINavigationController的
    • UiViewController1(Locked in Portrait) 初始视图控制器,在导航栏上放置一个button,使用户可以访问列表,在其中可以select其他视图
    • UIViewController2(locking在横向)
    • UiViewController3(纵向和横向)
    • UiViewController4(纵向和横向)

我怎样才能做到这一点?

根据Swift Apple Docs for SupportedInterfaceOrientations的说法:

讨论

当用户更改设备方向时,系统在根视图控制器或填充窗口的最顶层呈现视图控制器上调用此方法。 如果视图控制器支持新的方向,窗口和视图控制器将旋转到新的方向。 只有在视图控制器的shouldAutorotate方法返回true时,才会调用此方法。

您的导航控制器应该覆盖shouldAutorotatesupportedInterfaceOrientations ,如下所示。 为了方便UINavigationController我在UINavigationController扩展中做了这个:

 extension UINavigationController { public override func shouldAutorotate() -> Bool { return true } public override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return (visibleViewController?.supportedInterfaceOrientations())! } } 

而你的主视图控制器(任何时候都是肖像)应该有:

 override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } 

然后,在您想要支持纵向或横向的子视图控制器中:

 override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.All } 

编辑:更新为iOS 9 🙂

如果您的视图embedded在storyboard中的navigationcontroller中,则设置导航控制器委托UINavigationControllerDelegate并添加以下方法

 class ViewController: UIViewController, UINavigationControllerDelegate { func navigationControllerSupportedInterfaceOrientations(navigationController: UINavigationController) -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } } 

还回答了[这里]

如果有复杂的视图层次结构(如具有多个导航控制器和/或选项卡视图控制器),事情会变得相当混乱。

这个实现把它放在每个视图控制器上,以便当他们想locking方向时,而不是依靠App Delegate通过遍历子视图或依靠inheritance来find它们。

Swift 3

在AppDelegate中:

 /// set orientations you want to be allowed in this property by default var orientationLock = UIInterfaceOrientationMask.all func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask { return self.orientationLock } 

在其他一些全局结构或帮助器类中,在这里我创build了AppUtility:

 struct AppUtility { static func lockOrientation(_ orientation: UIInterfaceOrientationMask) { if let delegate = UIApplication.shared.delegate as? AppDelegate { delegate.orientationLock = orientation } } /// OPTIONAL Added method to adjust lock and rotate to the desired orientation static func lockOrientation(_ orientation: UIInterfaceOrientationMask, andRotateTo rotateOrientation:UIInterfaceOrientation) { self.lockOrientation(orientation) UIDevice.current.setValue(rotateOrientation.rawValue, forKey: "orientation") } } 

然后在所需的ViewController中,您要locking方向:

  override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) AppUtility.lockOrientation(.portrait) // Or to rotate and lock // AppUtility.lockOrientation(.portrait, andRotateTo: .portrait) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) // Don't forget to reset when view is being removed AppUtility.lockOrientation(.all) } 

更新:如果在iOS 10启动应用程序后遇到问题,请尝试在ObjC而不是Swift使用class MyNavigationController: MyNavigationControllerBase

 @implementation ABNavigationControllerBase - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } @end 

Swift 3:

 class MyNavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation") } override var shouldAutorotate: Bool { return false } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation { return .portrait } } 

重要的想法是在AppDelegate中描述整个应用程序支持的接口方向。 例如要阻止所有视图到肖像只是这样做:

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

很多人正在寻找这个答案通过谷歌search扔这个问题,所以我希望你能原谅我。

适用于Swift 3.0

在你想要肖像的主控制器里,

 - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.orientation = UIInterfaceOrientationMaskPortrait; //Or self.orientation = UIInterfaceOrientationPortraitUpsideDown } 

并在subVC你想要景观使用

  self.orientation = UIInterfaceOrientationLandscapeLeft: self.orientation = UIInterfaceOrientationLandscapeRight: 

或者你可以重写这个方法

 - (NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } 

这是我如何在iOS7中与Obj-c做到这一点,我认为这个代码也可以在iOS8中工作

这是Swift更新:

 override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } 

编辑为swift2.0:

 override func shouldAutorotate() -> Bool { return false } override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return [.Portrait, .PortraitUpsideDown] } 

这是Swift 3(XCode 8.2 beta)的语法,其中这些方法转换为属性:

 extension UINavigationController { override open var shouldAutorotate: Bool { return false } } class ViewController: UIViewController { /* ... */ override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return UIInterfaceOrientationMask.portrait } } 

你必须把它应用到你的顶级视图控制器。 但是,您可以通过子类化顶部视图控制器并在其中设置一个variables来以干净/简单的方式执行此操作,以便在每次调用时都引用该variables:

 shouldAutoRotate() 

当设备检测到方向改变并在调用之前:

 supportedInterfaceOrientations()//this is only called if shouldAutoRotate() returns true 

例如,说我的顶视图控制器是一个TabBarController:

 class SomeSubclassTabBarViewController: UITabBarController { //This subclass allows us to pass along data to each of the tabBars var dataArray = StoredValues()//also useful for passing info between tabs var shouldRotate: Bool = false override func shouldAutorotate() -> Bool { //allow the subviews accessing the tabBarController to set whether they should rotate or not return self.shouldRotate } 

}

然后在应该有能力旋转屏幕的视图内,设置viewWillAppear()和viewWillDisappear()如下所示:

 override func viewWillAppear(animated: Bool) { //set the rotate capability to true let sharedTabBarController = self.tabBarController as SomeSubclassTabBarViewController sharedTabBarController.shouldRotate = true } override func viewWillDisappear(animated: Bool) { let sharedTabBarController = self.tabBarController as SomeSubclassTabBarViewController sharedTabBarController.shouldRotate = false } 

并且为了防止您的应用在此屏幕上崩溃,最好在viewWillLoad()方法的每个视图中明确设置shouldRotate:Bool值。

在iOS8中,如果你想locking一些特定的ViewController,创build一个UINavigationController的扩展(在你使用它的情况下):

 extension UINavigationController { public override func shouldAutorotate() -> Bool { if visibleViewController is YourViewController { return false } return true }}