iOS 填坑系列 - 狀態(tài)欄變化

概述

相信很多iOS開發(fā)者都做過改變狀態(tài)欄樣式和隱藏狀態(tài)欄府适,這個功能也挺簡單的唯绍,但應該也有不少人踩過其中的坑啦粹。蘋果特別喜歡動不動就改偿荷,每個版本都不一樣,這個方法這個版本好好的唠椭,下個版本就非得用另外一種方式實現(xiàn)才行遭顶。而蘋果對于狀態(tài)欄修改的方式一直折騰不休,作為一個經(jīng)歷了從iOS 7 到 iOS 10開發(fā)者泪蔫,在這方面也一直被困擾著棒旗,一直不知道到底哪種方式才是正確的,每次都要試一試才敢確定撩荣。踩了太多坑铣揉,于是在這里總結(jié)一下吧。

本文是基于 iOS 10的餐曹,有些方面對比了 iOS 9 和 iOS 10 的異同逛拱,其他不同版本請Google。

隱藏和修改樣式

iOS 9 和 10 中台猴,默認情況下朽合,狀態(tài)欄的改變是通過 view-controlls 控制的俱两,由每個控制器決定狀態(tài)欄的樣式以及是否隱藏狀態(tài)欄。

只需在控制器中重載 prefersStatusBarHiddenpreferredStatusBarStyle就可以控制是否隱藏狀態(tài)欄以及修改狀態(tài)欄的樣式曹步。

// 隱藏狀態(tài)欄
override var prefersStatusBarHidden: Bool {
    return true
}

// 修改狀態(tài)欄的樣式為白色
override var preferredStatusBarStyle: UIStatusBarStyle {
    return .lightContent
}

全局控制狀態(tài)欄

iOS 9 中宪彩,全局控制狀態(tài)欄的改變,只需兩步:

  1. Info.plist中讲婚,添加屬性 View controller-based status bar appearance尿孔,設(shè)置為 NO
  2. 添加如下代碼:
// 修改狀態(tài)欄的樣式為白色
UIApplication.shared.setStatusBarStyle(.lightContent, animated: true)

// 隱藏狀態(tài)欄
UIApplication.shared.setStatusBarHidden(true, with: .fade)

注意:如果不設(shè)置View controller-based status bar appearance或設(shè)置為 YES,則上面兩句代碼不生效筹麸。

iOS 10 中活合,上述兩個方法已經(jīng)被棄用了,蘋果推薦使用在控制器中重載prefersStatusBarHiddenpreferredStatusBarStyle的方法來控制狀態(tài)欄的改變物赶。但是如果你硬是要使用的話白指,還是會有效果的,只不過會看到兩個警告罷了酵紫。

'setStatusBarStyle(_:animated:)' was deprecated in iOS 9.0: Use -[UIViewController preferredStatusBarStyle]
'setStatusBarHidden(_:with:)' was deprecated in iOS 9.0: Use -[UIViewController prefersStatusBarHidden]

如果不想看到這兩個警告告嘲,在 iOS 10 中,還有另外一種方式可以全局控制憨闰,除了設(shè)置View controller-based status bar appearanceNO外状蜗,需要修改【General】-->【Deployment Info】-->【Status Bar Style】。

改變狀態(tài)欄的方向

UIApplication.shared.statusBarOrientation = .portrait

填坑

狀態(tài)欄改變不了的情況

在一個控制器中添加一個 ChildViewController 鹉动,如果想在 ChildViewController 來控制狀態(tài)欄轧坎,就會失效。

解決辦法是:重載 childViewControllerForStatusBarHidden方法泽示,并在viewDidLoad中刷新一次狀態(tài)欄

class StatusBarHiddenParentController: UIViewController {
    
    var childController: StatusBarHiddenChildController?
    override func viewDidLoad() {
        super.viewDidLoad()
        childController = StatusBarHiddenChildController.fromStoryboard("Main")
        addChildViewController(childController!)
        view.addSubview(childController!.view)
        
        // 刷新狀態(tài)欄
        setNeedsStatusBarAppearanceUpdate()
    }
    override func childViewControllerForStatusBarHidden() -> UIViewController? {
        return childController
    }
    
    override func prefersStatusBarHidden() -> Bool {
        return false
    }
}

class StatusBarHiddenChildController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    override func prefersStatusBarHidden() -> Bool {
        return true
    }
}

還有一個需要注意的問題是缸血,當 ChildViewController 從父控制器中移除時,需要再次刷新狀態(tài)欄械筛,具體做法請參考我以前的文章 iOS Status Bar 的隱藏 捎泻。

在View中控制狀態(tài)欄的改變

我在做 JFPlayer 的時候,封裝了一個播放視頻的View埋哟,在播放器從窗口切換為全屏時笆豁,需要改變狀態(tài)欄的方向以及隱藏狀態(tài)欄。因為是要做成一個簡單易用的庫赤赊,所以要封裝的更徹底闯狱,不能把細節(jié)暴露出去,這時就要在View(而不是控制器)中改變狀態(tài)欄了抛计,有三個問題需要解決:

  • 項目中的View controller-based status bar appearance的值是YES還是NO哄孤,基于這個判斷是由控制器決定狀態(tài)欄還是全局控制。
  • 如果是控制器決定狀態(tài)欄吹截,那如何獲取該View的父控制器
  • 如果是控制器決定狀態(tài)欄瘦陈,那控制器如何知道此時是否應該隱藏呢
控制狀態(tài)欄
extension UIApplication {
    
    func jf_usesViewControllerBasedStatusBarAppearance() -> Bool {
        let key = "UIViewControllerBasedStatusBarAppearance"
        guard  let object = Bundle.main.object(forInfoDictionaryKey: key) else {
            return true
        }
        
        return (object as! Bool)
    }
    
    func jf_updateStatusBarAppearanceHidden(_ hidden: Bool, animation: UIStatusBarAnimation, fromViewController sender: UIViewController) {
        
        if jf_usesViewControllerBasedStatusBarAppearance() {
            sender.setNeedsStatusBarAppearanceUpdate()
        } else {
            UIApplication.shared.setStatusBarHidden(hidden, with: animation)
        }
    }
}

獲取View的父控制器
extension UIView {
    var parentViewController: UIViewController? {
        var parentResponder: UIResponder? = self
        while parentResponder != nil {
            parentResponder = parentResponder!.next
            if let viewController = parentResponder as? UIViewController {
                return viewController
            }
        }
        return nil
    }
}

第三個問題凝危,需要借助一個變量 statusBarIsHidden 標記下此時狀態(tài)欄是否該隱藏,并在控制器中重載prefersStatusBarHidden方法進行判斷晨逝。

實現(xiàn)代碼如下蛾默。

  1. 在點擊全屏按鈕時,改變狀態(tài)欄咏花,調(diào)用 updateStatusBarAppearanceHidden方法更新狀態(tài)欄
func fullScreenButtonPressed(_ button: UIButton?) {
        
    // force change device and status bar orientation, that toggle the UIApplicationDidChangeStatusBarOrientation notification
    if isFullScreen {
        
        UIDevice.current.setValue(UIInterfaceOrientation.portrait.rawValue, forKey: "orientation")
        updateStatusBarAppearanceHidden(false)
        UIApplication.shared.statusBarOrientation = .portrait
    } else {
        
        UIDevice.current.setValue(UIInterfaceOrientation.landscapeRight.rawValue, forKey: "orientation")
        updateStatusBarAppearanceHidden(false)
        UIApplication.shared.statusBarOrientation = .landscapeRight
    }
}

fileprivate func updateStatusBarAppearanceHidden(_ hidden: Bool) {
    statusBarIsHidden = hidden
    if let parentViewController = self.parentViewController {
        UIApplication.shared.jf_updateStatusBarAppearanceHidden(self.statusBarIsHidden, animation: .none, fromViewController: parentViewController)
    }
}

  1. 在控制器中重載 prefersStatusBarHidden
 override var prefersStatusBarHidden: Bool {
    guard let hidden = player?.statusBarIsHidden else {
        return false
    }
    return hidden
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末趴生,一起剝皮案震驚了整個濱河市阀趴,隨后出現(xiàn)的幾起案子昏翰,更是在濱河造成了極大的恐慌,老刑警劉巖刘急,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棚菊,死亡現(xiàn)場離奇詭異,居然都是意外死亡叔汁,警方通過查閱死者的電腦和手機统求,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來据块,“玉大人码邻,你說我怎么就攤上這事×砑伲” “怎么了像屋?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長边篮。 經(jīng)常有香客問我己莺,道長,這世上最難降的妖魔是什么戈轿? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任凌受,我火速辦了婚禮,結(jié)果婚禮上思杯,老公的妹妹穿的比我還像新娘胜蛉。我一直安慰自己,他們只是感情好色乾,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布誊册。 她就那樣靜靜地躺著,像睡著了一般杈湾。 火紅的嫁衣襯著肌膚如雪解虱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天漆撞,我揣著相機與錄音殴泰,去河邊找鬼于宙。 笑死,一個胖子當著我的面吹牛悍汛,可吹牛的內(nèi)容都是我干的捞魁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼离咐,長吁一口氣:“原來是場噩夢啊……” “哼谱俭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起宵蛀,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤昆著,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后术陶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凑懂,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年梧宫,在試婚紗的時候發(fā)現(xiàn)自己被綠了接谨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡塘匣,死狀恐怖脓豪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情忌卤,我是刑警寧澤扫夜,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站埠巨,受9級特大地震影響历谍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辣垒,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一望侈、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧勋桶,春花似錦脱衙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鹃锈,卻和暖如春荤胁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背屎债。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工仅政, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留垢油,地道東北人。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓圆丹,卻偏偏與公主長得像滩愁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子辫封,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 正如每個java文檔所描述的那樣硝枉,CountDownLatch是一個同步工具類投慈,它允許一個或多個線程一直等待尉辑,直到...
    algernoon閱讀 550評論 0 1
  • 午飯過后铡俐,我看著《綠》赠幕,弟弟看動畫片;叔叔看今日頭條袱院,嬸嬸在清洗碗筷嘁字,一切一如往常。 門被打開了劣欢,妹妹從學校補習功...
    凡心未了閱讀 259評論 0 0
  • 上初中后才接觸到幻燈片(ppt),那時候最感興趣的莫過于各種淡入淡出裁良、彈出凿将、百葉窗的動畫效果,如果某位同學做了一個...
    大臉貓撿破爛閱讀 982評論 0 0
  • 男人遠比你想像中要脆弱犀变,也許你還沒靠上去,他們就倒了秋柄。 早上看了一篇文章获枝,提到女人的兩條出路,一條是讀大學骇笔,知識改...
    或者時光閱讀 1,365評論 0 0
  • 今天與許久不聯(lián)系的老同桌聊天笨触,海南大學商務英語專業(yè)懦傍,前不久剛拿到美國加州大學伯克利分校的offer,10號就要去...
    夢中的安妮小姐閱讀 289評論 0 1