APP内单个VC支持Landscape
2016-06-22 本文已影响158人
Dev端
昨天在做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
}
}