有些時候我們需要用特定方向展示某些頁面(例如固定橫屏展示)甘邀,而不影響其它頁面琅攘。例如一些 app 固定用橫屏播放視頻。這種情況下坞琴,我們就需要在代碼中控制。
注:所有代碼均使用 Swift 4.0
要點
- 涉及的 view controller 屬性:
shouldAutorotate
,supportedInterfaceOrientations
,preferredInterfaceOrientationForPresentation
- info.plist 的 Device Orientation 需要把所有會在 app 里出現(xiàn)的頁面方向選上置济,如下圖:
- 當(dāng)使用 container controller (
UITabBarController
,UINavigationController
)包裹 view controller 時,系統(tǒng)通過查詢 container controller 的
supportedInterfaceOrientations
和shouldAutorotate
屬性來決定方向- 注意:在 navigation controller push/pop view controller锋八,或在 tab bar controller 里改變 selected view controller時浙于,不應(yīng)該改變 view controller 的頁面方向。因為前后 view controller 頁面方向不同的話挟纱,會出現(xiàn)不連貫的奇怪過場動畫羞酗,更重要的是也不符合 container controller 的使用標(biāo)準(zhǔn)。下面會用例子說明紊服。
- 當(dāng) present view controller 時胸竞,系統(tǒng)則通過查詢 presented view controller 的
supportedInterfaceOrientations
,shouldAutorotate
,preferredInterfaceOrientationForPresentation
三個屬性來決定方向
官方文檔解釋
在看代碼之前,需要先了解這三個屬性的定義卫枝。
shouldAutorotate: Bool 類型的屬性,決定能否切換頁面方向校赤。默認(rèn)情況下返回 true, 需要配合著
supportedInterfaceOrientations
使用,看條目supportedInterfaceOrientations
的解釋筒溃。supportedInterfaceOrientations: bit mask 類型的屬性,Swift 下可以使用
UIInterfaceOrientation
enum 值的 Set 表示怜奖。使用情景是當(dāng)系統(tǒng)檢測到設(shè)備方向改變時,會訪問 container controller 或 presented view controller 的這個屬性來獲取目前所支持的頁面方向歪玲,當(dāng)返回值包括設(shè)備新的頁面方向時迁央,系統(tǒng)會繼續(xù)訪問shouldAutorotate
來決定是否旋轉(zhuǎn)頁面读慎;當(dāng)返回值不包括時,系統(tǒng)則不會繼續(xù)訪問shouldAutorotate
夭委。-
preferredInterfaceOrientationForPresentation:
UIInterfaceOrientation
enum 類型的屬性,當(dāng)在 full screen 下 present view controller 時株灸,系統(tǒng)訪問此屬性來決定 presented view controller 的頁面方向。這里要注意兩點:- 只有在
modalPresentationStyle
為 full screen 時才適用慌烧,其它 style 下不會被訪問 -
preferredInterfaceOrientationForPresentation
必須是supportedInterfaceOrientations
的子集,否則當(dāng) present 此頁面時 app 會強退
- 只有在
單純文字太抽象屹蚊,以下通過代碼來詳細描述各個情況下的設(shè)定厕氨。所有代碼均使用 Swift 4 書寫汹粤,如果是 Objective-C, override 相應(yīng)方法即可。
使用 container controller 的例子
例子使用 tab bar controller -> navigation controller -> view controller 的層級結(jié)構(gòu):
根據(jù)所在頁面控制是否跟隨設(shè)備方向來改變頁面方向的效果:
實現(xiàn)思路是嘱兼,在所有 container 里實現(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 里就可以返回需要的值來決定起頁面方向配置接奈。
注意:不建議在同一個 container controller 里前后 view controller 方向不一致的設(shè)定,否則會出現(xiàn)不對稱的過場動畫序宦。
如下例子是豎屏 push,橫屏 pop 后利虫,下次豎屏 push 完后的豎屏 pop 動畫還是會和橫屏 pop 一樣:
目前我知道的解決辦法是:在可以變換頁面方向的 view controller 里換回豎屏 pop挨厚。
Present 例子
Present view controller 相對來說自由很多糠惫,個人認(rèn)為是因為這種方式無論是相互關(guān)系和 UI 關(guān)聯(lián)性都比較獨立于 container controller钉疫。你可以 present 任意方向的 view controller硼讽,同時 dismiss 時的方向也不會影響下次 present 后的 dismiss 方向牲阁。
一個固定 landscapeLeft present 的例子:
present 需要在 presented view controller 里實現(xiàn)三個屬性:
override var shouldAutorotate: Bool {
return false
}
override var preferredInterfaceOrientationForPresentation: UIInterfaceOrientation {
return .landscapeLeft
}
override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
return .landscapeLeft
}
上文提過,present 的這種使用需要 modalPresentationStyle
為 full screen 且 preferredInterfaceOrientationForPresentation
必須是 supportedInterfaceOrientations
的子集城菊。
同時這里多實現(xiàn)的 preferredInterfaceOrientationForPresentation
是用于控制 presented view controller 出現(xiàn)時的方向。無論設(shè)備或者 presenting view controller 是什么方向凌唬,presented view controller 的方向都會根據(jù)此屬性來設(shè)置。
總結(jié)
- view controller 的頁面橫豎屏通過三個屬性控制:
shouldAutorotate
客税,preferredInterfaceOrientationForPresentation
况褪,supportedInterfaceOrientations
- info.plist 的 Device Orientation 需要包括 app 里所有可能出現(xiàn)的頁面方向
- 當(dāng)使用 container controller 時更耻,系統(tǒng)通過調(diào)用 container controller 的
shouldAutorotate
和supportedInterfaceOrientations
來決定方向- container controller 里的前后 view controllers 的方向建議保持一致
- 當(dāng) present view controller 時,系統(tǒng)通過調(diào)用presented view controller 的
shouldAutorotate
秧均,preferredInterfaceOrientationForPresentation
食侮,supportedInterfaceOrientations
來決定方向
歡迎任何意見交流 :)
實例項目請點 這里