有些時(shí)候我們需要用特定方向展示某些頁(yè)面(例如固定橫屏展示),而不影響其它頁(yè)面。例如一些 app 固定用橫屏播放視頻。這種情況下,我們就需要在代碼中控制。
注:所有代碼均使用 Swift 4.0
要點(diǎn)
- 涉及的 view controller 屬性:
shouldAutorotate,supportedInterfaceOrientations,preferredInterfaceOrientationForPresentation - info.plist 的 Device Orientation 需要把所有會(huì)在 app 里出現(xiàn)的頁(yè)面方向選上,如下圖:

- 當(dāng)使用 container controller (
UITabBarController,UINavigationController)包裹 view controller 時(shí),系統(tǒng)通過查詢 container controller 的
supportedInterfaceOrientations和shouldAutorotate屬性來(lái)決定方向- 注意:在 navigation controller push/pop view controller,或在 tab bar controller 里改變 selected view controller時(shí),不應(yīng)該改變 view controller 的頁(yè)面方向。因?yàn)榍昂?view controller 頁(yè)面方向不同的話,會(huì)出現(xiàn)不連貫的奇怪過場(chǎng)動(dòng)畫,更重要的是也不符合 container controller 的使用標(biāo)準(zhǔn)。下面會(huì)用例子說(shuō)明。
- 當(dāng) present view controller 時(shí),系統(tǒng)則通過查詢 presented view controller 的
supportedInterfaceOrientations,shouldAutorotate,preferredInterfaceOrientationForPresentation三個(gè)屬性來(lái)決定方向
官方文檔解釋
在看代碼之前,需要先了解這三個(gè)屬性的定義。
shouldAutorotate: Bool 類型的屬性,決定能否切換頁(yè)面方向。默認(rèn)情況下返回 true, 需要配合著
supportedInterfaceOrientations使用,看條目supportedInterfaceOrientations的解釋。supportedInterfaceOrientations: bit mask 類型的屬性,Swift 下可以使用
UIInterfaceOrientationenum 值的 Set 表示。使用情景是當(dāng)系統(tǒng)檢測(cè)到設(shè)備方向改變時(shí),會(huì)訪問 container controller 或 presented view controller 的這個(gè)屬性來(lái)獲取目前所支持的頁(yè)面方向,當(dāng)返回值包括設(shè)備新的頁(yè)面方向時(shí),系統(tǒng)會(huì)繼續(xù)訪問shouldAutorotate來(lái)決定是否旋轉(zhuǎn)頁(yè)面;當(dāng)返回值不包括時(shí),系統(tǒng)則不會(huì)繼續(xù)訪問shouldAutorotate。-
preferredInterfaceOrientationForPresentation:
UIInterfaceOrientationenum 類型的屬性,當(dāng)在 full screen 下 present view controller 時(shí),系統(tǒng)訪問此屬性來(lái)決定 presented view controller 的頁(yè)面方向。這里要注意兩點(diǎn):- 只有在
modalPresentationStyle為 full screen 時(shí)才適用,其它 style 下不會(huì)被訪問 -
preferredInterfaceOrientationForPresentation必須是supportedInterfaceOrientations的子集,否則當(dāng) present 此頁(yè)面時(shí) app 會(huì)強(qiáng)退
- 只有在
單純文字太抽象,以下通過代碼來(lái)詳細(xì)描述各個(gè)情況下的設(shè)定。所有代碼均使用 Swift 4 書寫,如果是 Objective-C, override 相應(yīng)方法即可。
使用 container controller 的例子
例子使用 tab bar controller -> navigation controller -> view controller 的層級(jí)結(jié)構(gòu):

根據(jù)所在頁(yè)面控制是否跟隨設(shè)備方向來(lái)改變頁(yè)面方向的效果:

實(shí)現(xiàn)思路是,在所有 container 里實(shí)現(xiàn) shouldAutorotate 和 supportedInterfaceOrientations,返回展示的最上層的 view controller 的設(shè)置。
在 tabbar controller 里:
override var shouldAutorotate: Bool {
return selectedViewController?.shouldAutorotate ?? false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return selectedViewController?.supportedInterfaceOrientations ?? .portrait
}
在 navigation controller 里:
override var shouldAutorotate: Bool {
return topViewController?.shouldAutorotate ?? false
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return topViewController?.supportedInterfaceOrientations ?? .portrait
}
因此在 view controller 里就可以返回需要的值來(lái)決定起頁(yè)面方向配置。
注意:不建議在同一個(gè) container controller 里前后 view controller 方向不一致的設(shè)定,否則會(huì)出現(xiàn)不對(duì)稱的過場(chǎng)動(dòng)畫。
如下例子是豎屏 push,橫屏 pop 后,下次豎屏 push 完后的豎屏 pop 動(dòng)畫還是會(huì)和橫屏 pop 一樣:

目前我知道的解決辦法是:在可以變換頁(yè)面方向的 view controller 里換回豎屏 pop。
Present 例子
Present view controller 相對(duì)來(lái)說(shuō)自由很多,個(gè)人認(rèn)為是因?yàn)檫@種方式無(wú)論是相互關(guān)系和 UI 關(guān)聯(lián)性都比較獨(dú)立于 container controller。你可以 present 任意方向的 view controller,同時(shí) dismiss 時(shí)的方向也不會(huì)影響下次 present 后的 dismiss 方向。
一個(gè)固定 landscapeLeft present 的例子:

present 需要在 presented view controller 里實(shí)現(xiàn)三個(gè)屬性:
override var shouldAutorotate: Bool {
return false
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}
上文提過,present 的這種使用需要 modalPresentationStyle 為 full screen 且 preferredInterfaceOrientationForPresentation 必須是 supportedInterfaceOrientations 的子集。
同時(shí)這里多實(shí)現(xiàn)的 preferredInterfaceOrientationForPresentation 是用于控制 presented view controller 出現(xiàn)時(shí)的方向。無(wú)論設(shè)備或者 presenting view controller 是什么方向,presented view controller 的方向都會(huì)根據(jù)此屬性來(lái)設(shè)置。
總結(jié)
- view controller 的頁(yè)面橫豎屏通過三個(gè)屬性控制:
shouldAutorotate,preferredInterfaceOrientationForPresentation,supportedInterfaceOrientations - info.plist 的 Device Orientation 需要包括 app 里所有可能出現(xiàn)的頁(yè)面方向
- 當(dāng)使用 container controller 時(shí),系統(tǒng)通過調(diào)用 container controller 的
shouldAutorotate和supportedInterfaceOrientations來(lái)決定方向- container controller 里的前后 view controllers 的方向建議保持一致
- 當(dāng) present view controller 時(shí),系統(tǒng)通過調(diào)用presented view controller 的
shouldAutorotate,preferredInterfaceOrientationForPresentation,supportedInterfaceOrientations來(lái)決定方向
歡迎任何意見交流 :)
實(shí)例項(xiàng)目請(qǐng)點(diǎn) 這里