iOS 靈活的控制狀態列StatusBar

weixin_34290000發表於2018-11-29

在一個App的所有頁面中,總是會有幾個頁面的StatusBar與整體風格不一致。
比如有個特殊頁面StatusBar需要隱藏;另一個頁面StatusBar需要改為白色……
(╯°□°)╯︵┻━┻

想來每個iOS開發者都遇到過這樣的問題。

那麼,怎樣才能靈活的控制StatusBar的風格和顯示隱藏,並且在頁面之間跳轉時又不會顯得違和或突兀呢?

以這樣的專案結構為例:

  • LaunchScreen頁面的StatusBar隱藏,進入App主頁後StatusBar顯示;
  • 整個App採用「TabBarController -> NavigationController -> ViewController」這樣常見的結構;
  • 在Push ViewController的過程中,有些頁面隱藏StatusBar,有些頁面的UIStatusBarStyle會改變
1. LaunchScreen頁面的StatusBar隱藏

只需要找到Targets -> General -> Deployment Info中的Hide status bar,勾上左邊的勾就行了。

2710049-57b3374421d8e801.png
隱藏LaunchScreen的StatusBar

2. 修改info.plist配置

在info.plist中增加View controller-based status bar appearance,並將其值設定為YES
這個key的含義顧名思義:StatusBar的外觀基於ViewController。

眾所周知,控制StatusBar的風格和顯示隱藏有兩種方法:

  • UIApplication
UIApplication.shared.setStatusBarHidden(true, with: .slide);
UIApplication.shared.setStatusBarStyle(.default, animated: true)
  • UIViewController
override var prefersStatusBarHidden: Bool {
    return true
}

override var preferredStatusBarStyle: UIStatusBarStyle {
    return .default
}

第一種方法在iOS9中已經被棄用了,而第二種方法是iOS7時就有的API,也是蘋果推薦使用的方式。

根據上面的兩種方法,再結合View controller-based status bar appearance的含義,可以知道:

當設定為預設的NO時,意為不基於ViewController,而是基於UIApplication.shared.statusBarStyleUIApplication.shared.isStatusBarHidden。這時ViewController中的prefersStatusBarHiddenpreferredStatusBarStyle也根本不會被呼叫。

當設定為YES時,就是基於ViewController了,prefersStatusBarHiddenpreferredStatusBarStyle將會被正常呼叫。

3. 傳遞StatusBar控制權

想要靈活的控制StatusBar,必須能夠細化到每一個ViewController都有權利控制它自己頁面上的StatusBar的外觀。
但是,prefersStatusBarHiddenpreferredStatusBarStyle只會在keyWindow.rootViewController中被呼叫。
在本文的App檢視結構中,就是隻會在TabBarController中被呼叫。因此,這兩個方法必須寫到TabBarController中。

那怎麼將控制權傳遞到螢幕最上方顯示的ViewController中呢?

首先,要為NavigationController和ViewController建立基類;TabBarController一般只有一個,就沒必要建立基類了,專案中存在一個子類化的UITabBarController就可以了。

然後:

TabBarController中增加如下程式碼:

// MARK: - Status Bar
    
override var prefersStatusBarHidden: Bool {
    guard let selectedVC = selectedViewController else { return false }
    
    return selectedVC.prefersStatusBarHidden
}
    
override var preferredStatusBarStyle: UIStatusBarStyle {
    guard let selectedVC = selectedViewController else { return .default }

    return selectedVC.preferredStatusBarStyle
}

NavigationController基類中增加如下程式碼:

// MARK: - Status Bar
    
override var prefersStatusBarHidden: Bool {
    guard let topVC = topViewController else { return false }

    return topVC.prefersStatusBarHidden
}
    
override var preferredStatusBarStyle: UIStatusBarStyle {
    guard let topVC = topViewController else { return .default }

    return topVC.preferredStatusBarStyle
}

這樣,就可以將StatusBar的控制權傳遞給螢幕最上方的ViewController了,而在ViewController的基類中,也需要增加如下程式碼,以配置預設的StatusBar外觀。

// MARK: - Status Bar
    
override var prefersStatusBarHidden: Bool {
    // 預設顯示StatusBar
    return false
}
    
override var preferredStatusBarStyle: UIStatusBarStyle {
    // 預設風格
    return .default
}

在某些特殊頁面,需要改變StatusBar的風格和顯示隱藏時,在該ViewController中override上述兩個方法,return合適的結果就可以了。

最後,這裡是Demo地址。使用時記得先把Scheme切換到StatusBarDemo上哦!

相關文章