iOS方向控制
1、工程中Plist、AppDelegate、TabbarController、NavigationController、ViewController这些都可以控制方向,它们之间有什么关联?
当屏幕发生旋转的时候(前提是系统的方向控制开关打开),系统是最开始询问App的plist配置,如果配置只支持一个方向就不会向下询问了。如果支持多个方向会询问window的delegate,同样如果代理方法里面只支持一个方向就不会向下询问。如果代理方法里面支持多个方向window会去询问RootController比如TabbarController。到了Controller这一级,如果不主动询问下一级的方向,下一级的控制是会被忽略的。
2、工程中Plist只支持一个方向,比如Portrait,但是通过手动设置UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
屏幕方向会变化吗?
会变化,这个方法是打破规范的一个非公开 API方法。会突破plist屏障,直接从window的AppDelegate开始。但是我们很多场景又必须用到,比如视频App,不支持根据系统方向旋转,但是又可以手动控制屏幕横屏。
3、视频App场景下的实践?
Plist只支持Portrait;
屏蔽掉系统旋转,shouldAutorotate = false,不写默认就是;
AppDelegate支持可能出现的多种方向,.allButUpsideDown;
TabbarController,NavigationController,全部指向当前显示的Controller的方向;
基类Controller,封装方向控制,开放一个变量isContentPortrait给子类使用:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// --- ViewController基类 ---
open override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.view.backgroundColor = .white
if isContentPortrait, !UIDevice.isPortrait {
UIDevice.forcePortrait()
}
if !isContentPortrait, UIDevice.isPortrait {
UIDevice.forceLandscapeRight()
}
}
// --- UIDevice+ ---
public extension UIDevice {
/// 是否为竖直界面
static var isPortrait: Bool = true
/// 是否支持界面旋转
static var isSupportedRotate: Bool = false
/// 强制竖屏
static func forcePortrait() {
isPortrait = true
UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
/// 强制横屏(右方向)
static func forceLandscapeRight() {
isPortrait = false
UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
UIViewController.attemptRotationToDeviceOrientation()
}
}需要注意,window类型弹窗等逃离controller链条的页面。可能一个横屏视频全屏页面,弹窗会变成竖直的,这里需要手动控制。如果需要继承当前页面的方向,设置如下代码即可:
1
2
3
4
5
6
7override public func viewDidLoad() {
super.viewDidLoad()
modalTransitionStyle = .crossDissolve
modalPresentationStyle = .overFullScreen
view.backgroundColor = UIColor(hex: 0x000000, transparency: 0.65)
isContentPortrait = UIDevice.isPortrait
}