APP内单个VC支持Landscape

昨天在做App内视频播放器模块碰到的问题, 要达到的效果如下:
App本身是要只支持Portrait的,当且仅当到达视频播放器的时候支持Landscape.

讲道理应该会有强制设备旋转的方法,在StackOverflow上有这样一个问题: How to force view controller orientation in iOS 8?,投票第一的答案就是解决这个问题的,然而iOS9这个方法已经无用.

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

修复强制旋转屏幕的可用性的办法是修改AppDelegate里的一个方法:

func application(application: UIApplication, supportedInterfaceOrientationsForWindow window: UIWindow?) -> UIInterfaceOrientationMask {
    if let topController = UIViewController.topMostViewController() {
        if topController is XXViewController {
            return [.Portrait, .LandscapeLeft]
        }
    }
    return [.Portrait]
}

这个方法在每次设备检测到屏幕有旋转倾向的时候都会被调用,包括内部调用和外部旋转, 这里找到最上层的ViewController, 判定当且仅当顶层是特定的ViewController的时候才会支持LandScape.

这样设置之后,强制旋转屏幕的KVO方法又再次生效了:

let value = UIInterfaceOrientation.LandscapeLeft.rawValue
UIDevice.currentDevice().setValue(value, forKey: "orientation")

然而,这两行代码始终还是不安全的,指不定哪天苹果又用一些新的方法去限制这种强制调用. 其实真正正确的做法是在项目Target->Device Orientation里勾上所有有可能支持的orientation,然后在每个VC里重写下面这个方法来对VC做出限制.

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

但是面临的问题就是每一个VC都要多这3行代码. 囧.

有时候hacking还是不hacking,难选择呢....

最后贴一下Utils Func:

extension UIViewController {

    /// Returns the current application's top most view controller.
    public class func topMostViewController() -> UIViewController? {
        let rootViewController = UIApplication.sharedApplication().windows.first?.rootViewController
        return self.topMostViewControllerOfViewController(rootViewController)
    }



    /// Returns the top most view controller from given view controller's stack.
    class func topMostViewControllerOfViewController(viewController: UIViewController?) -> UIViewController? {
        // UITabBarController
        if let tabBarController = viewController as? UITabBarController,
           let selectedViewController = tabBarController.selectedViewController {
            return self.topMostViewControllerOfViewController(selectedViewController)
        }

        // UINavigationController
        if let navigationController = viewController as? UINavigationController,
           let visibleViewController = navigationController.visibleViewController {
            return self.topMostViewControllerOfViewController(visibleViewController)
        }

        // presented view controller
        if let presentedViewController = viewController?.presentedViewController {
            return self.topMostViewControllerOfViewController(presentedViewController)
        }

        // child view controller
        for subview in viewController?.view?.subviews ?? [] {
            if let childViewController = subview.nextResponder() as? UIViewController {
                return self.topMostViewControllerOfViewController(childViewController)
            }
        }

        return viewController
    }

}

推荐阅读更多精彩内容

  • iOS屏幕旋转学习笔记iOS开发中使用屏幕旋转功能的相关方法 1、基本知识点解读 了解屏幕旋转首先需要区分两种 o...
    Laughingg阅读 11,232评论 13 37
  • 1.监听屏幕旋转方向 在处理iOS横竖屏时,经常会和UIDeviceOrientation、UIInterface...
    彬至睢阳阅读 996评论 1 5
  • /* UIViewController is a generic controller base class th...
    DanDanC阅读 713评论 0 1
  • 1、UIDeviceOrientation 设备的物理方向 简介UIDeviceOrientation即我们手持的...
    MrJ的杂货铺阅读 17,314评论 7 64
  • 1.读书。俗话说:一本好书就是一位良师,一位益友。新的一年一定要与书为友,多读书,读好书。必读的书目《一个人的朝圣...
    大大大辉狼阅读 17评论 0 0