iOS - 自由控制頁(yè)面橫豎屏展示

有些時(shí)候我們需要用特定方向展示某些頁(yè)面(例如固定橫屏展示),而不影響其它頁(yè)面。例如一些 app 固定用橫屏播放視頻。這種情況下,我們就需要在代碼中控制。

注:所有代碼均使用 Swift 4.0

要點(diǎn)

  1. 涉及的 view controller 屬性:shouldAutorotate, supportedInterfaceOrientations, preferredInterfaceOrientationForPresentation
  2. info.plistDevice Orientation 需要把所有會(huì)在 app 里出現(xiàn)的頁(yè)面方向選上,如下圖:
info.plist 里的 Device Orientation
  1. 當(dāng)使用 container controller (UITabBarController, UINavigationController)包裹 view controller 時(shí),系統(tǒng)通過查詢 container controller 的
    supportedInterfaceOrientationsshouldAutorotate 屬性來(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ō)明。
  2. 當(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 下可以使用 UIInterfaceOrientation enum 值的 Set 表示。使用情景是當(dāng)系統(tǒng)檢測(cè)到設(shè)備方向改變時(shí),會(huì)訪問 container controllerpresented 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: UIInterfaceOrientation enum 類型的屬性,當(dāng)在 full screen 下 present view controller 時(shí),系統(tǒng)訪問此屬性來(lái)決定 presented view controller 的頁(yè)面方向。這里要注意兩點(diǎn):

    1. 只有在 modalPresentationStylefull screen 時(shí)才適用,其它 style 下不會(huì)被訪問
    2. 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):

view controller 結(jié)構(gòu)

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

在 container controller 里控制頁(yè)面方向

實(shí)現(xiàn)思路是,在所有 container 里實(shí)現(xiàn) shouldAutorotatesupportedInterfaceOrientations,返回展示的最上層的 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 一樣:

依舊是橫屏 pop 的過場(chǎng)動(dòng)畫

目前我知道的解決辦法是:在可以變換頁(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 的例子:

固定 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 的這種使用需要 modalPresentationStylefull screenpreferredInterfaceOrientationForPresentation 必須是 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.plistDevice Orientation 需要包括 app 里所有可能出現(xiàn)的頁(yè)面方向
  • 當(dāng)使用 container controller 時(shí),系統(tǒng)通過調(diào)用 container controller 的 shouldAutorotatesupportedInterfaceOrientations 來(lái)決定方向
    • container controller 里的前后 view controllers 的方向建議保持一致
  • 當(dāng) present view controller 時(shí),系統(tǒng)通過調(diào)用presented view controllershouldAutorotate,preferredInterfaceOrientationForPresentation,supportedInterfaceOrientations 來(lái)決定方向

歡迎任何意見交流 :)
實(shí)例項(xiàng)目請(qǐng)點(diǎn) 這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • /* UIViewController is a generic controller base class th...
    DanDanC閱讀 2,056評(píng)論 0 2
  • iOS中,使用ViewController進(jìn)行頁(yè)面跳轉(zhuǎn)的方法有很多,之前總是想到哪用到哪,最近在review項(xiàng)目的...
    ac3閱讀 18,838評(píng)論 2 60
  • 轉(zhuǎn)載自:https://github.com/Tim9Liu9/TimLiu-iOS 目錄 UI下拉刷新模糊效果A...
    袁俊亮技術(shù)博客閱讀 12,152評(píng)論 9 105
  • Harvey沒說(shuō)什么,只是皺著眉看著Mike的手,“你不去包扎一下嗎?”Mike愣了一會(huì)兒,顯然還沒從剛才的事件中...
    一酒貓餅閱讀 556評(píng)論 0 1
  • 三毛說(shuō):心若沒有棲息的地方,走到哪里都是流浪。 如同此刻的我, 走在這世界上,擁擠的人海中, 是沉默的,是孤獨(dú)的,...
    乃見閱讀 226評(píng)論 0 1

友情鏈接更多精彩內(nèi)容