首页 文章

如何使用swift仅锁定主视图的纵向方向

提问于
浏览
39

我使用 swift 为iPhone创建了一个应用程序,它由嵌入在导航控制器中的许多视图组成 . 我想将主视图锁定为纵向方向,并且仅锁定横向方向的导航控制器的子视图 . 这是我的意思的一个例子:

  • UINavigationController

  • UiViewController1(纵向锁定)初始视图控制器,导航栏上有一个按钮,可以让用户访问可以选择其他视图的列表

  • UIViewController2(景观锁定)

  • UiViewController3(人像与风景)

  • UiViewController4(人像与风景)

  • ......

  • ......

我怎样才能做到这一点?

12 回答

  • 17

    根据Swift Apple Docs for supportedInterfaceOrientations

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

    您的导航控制器应覆盖 shouldAutorotatesupportedInterfaceOrientations ,如下所示 . 为了方便起见,我在 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更新:-)

  • 0

    也回答[here]

    当您拥有复杂的视图层次结构时,例如拥有多个导航控制器和/或选项卡视图控制器,事情就会变得非常混乱 .

    此实现将其置于各个视图控制器上以设置何时锁定方向,而不是依靠App Delegate通过迭代子视图或依赖继承来查找它们 .

    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
    }
    

    在其他一些全局struct或helper类中,我在这里创建了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中,您想要锁定方向:

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

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

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

    更新:如果您在 iOS 10 中启动应用后无法立即设置方向,请尝试在 ObjC 而不是 Swift 中使用,并使用 class MyNavigationController: MyNavigationControllerBase

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

    斯威夫特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
        }
    }
    
  • 0

    Swift 4 中的 JasonJasonJason 回答(它与 iOS 11 一起正常工作)

    1- Override shouldAutorotate and supportedInterfaceOrientations as shown below.

    extension UINavigationController {
    
    open override var shouldAutorotate: Bool {
        return true;
    }
    
    open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return (visibleViewController?.supportedInterfaceOrientations)!;
    }}
    

    2- And your main viewcontroller (portrait at all times), should have:

    public override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.portrait;
    }
    

    3- Then, in your subviewcontrollers that you want to support portrait or landscape:

    public override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
        return UIInterfaceOrientationMask.all;
    }
    
  • 2

    重要的想法是在AppDelegate中描述整个应用程序支持的接口方向 . 例如,要将所有视图阻止为纵向,只需执行以下操作:

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

    很多人都在寻找这个答案谷歌搜索这个问题,所以我希望你能原谅我 .

    适用于Swift 3.0

  • 4

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

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

    在subVC中你想要使用Landscape

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

    或者您可以覆盖此方法

    - (NSUInteger)supportedInterfaceOrientations
    {
      return UIInterfaceOrientationMaskPortrait;
    }
    

    这就是我在iOS7中使用Obj-c的方式,我认为这段代码也适用于iOS8

  • 1

    这是Swift更新: -

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

    编辑swift2.0:

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

    这是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
        }
    }
    
  • 3

    您必须将此应用于顶视图控制器 . 但是,您可以通过子类化顶视图控制器并在其中设置一个变量来以干净/简单的方式执行此操作,以便在每次调用时引用:

    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值可能是个好主意 .

  • 6

    在iOS8中,如果要锁定某些特定的ViewController,请创建UINavigationController的扩展(在您使用它的情况下):

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

相关问题