記 iOS Status Bar 狀態欄 的一次革命

時隔多多多多多日,突然又又又又又又想寫點東西了!寫這篇文章呢,主要有兩個想法:對於初學的小弟弟們,講清楚一個知識點的歷史走向,梳理順向的開發流程,做到在項目經理的催活洪流中有條不紊。對於有些經驗可做談資的大哥哥們,可以借鑑蘋果系統的設計模式和工作理念,從中吸取完美框架的設計思路。我僅代表伍麗娟祝大家七夕節快樂。

狀態欄的發展洪流

咳咳,瓜子準備好了麼?如果沒有準備好,請到我的微博第一條置頂微博處免費領取,下面請用心的欣賞我的表演。

2007年,iOS隨iPhone亮相,開發者們覺得呢,我的電池欄總是白底黑字,不能適應我司產品詭異且有豐滿的樣式追求呀。響應大家號召,隨即iOS2於2008年7月11日上市,帶來了關於狀態欄的一系列操作的API,隨即iOS3.2對這套API的進行了優化,大家可以從下面的代碼中稍微的領悟一下。

@interface UIApplication()

@property(nonatomic,getter=isProximitySensingEnabled) BOOL proximitySensingEnabled NS_DEPRECATED_IOS(2_0, 3_0) __TVOS_PROHIBITED; // default is NO. see UIDevice for replacement
- (void)setStatusBarHidden:(BOOL)hidden animated:(BOOL)animated NS_DEPRECATED_IOS(2_0, 3_2) __TVOS_PROHIBITED; // use -setStatusBarHidden:withAnimation:

// Explicit setting of the status bar orientation is more limited in iOS 6.0 and later.
@property(readwrite, nonatomic) UIInterfaceOrientation statusBarOrientation NS_DEPRECATED_IOS(2_0, 9_0, "Explicit setting of the status bar orientation is more limited in iOS 6.0 and later") __TVOS_PROHIBITED;
- (void)setStatusBarOrientation:(UIInterfaceOrientation)interfaceOrientation animated:(BOOL)animated NS_DEPRECATED_IOS(2_0, 9_0, "Explicit setting of the status bar orientation is more limited in iOS 6.0 and later") __TVOS_PROHIBITED;

// Setting the statusBarStyle does nothing if your application is using the default UIViewController-based status bar system.
@property(readwrite, nonatomic) UIStatusBarStyle statusBarStyle NS_DEPRECATED_IOS(2_0, 9_0, "Use -[UIViewController preferredStatusBarStyle]") __TVOS_PROHIBITED;
- (void)setStatusBarStyle:(UIStatusBarStyle)statusBarStyle animated:(BOOL)animated NS_DEPRECATED_IOS(2_0, 9_0, "Use -[UIViewController preferredStatusBarStyle]") __TVOS_PROHIBITED;

// Setting statusBarHidden does nothing if your application is using the default UIViewController-based status bar system.
@property(readwrite, nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden NS_DEPRECATED_IOS(2_0, 9_0, "Use -[UIViewController prefersStatusBarHidden]") __TVOS_PROHIBITED;
- (void)setStatusBarHidden:(BOOL)hidden withAnimation:(UIStatusBarAnimation)animation NS_DEPRECATED_IOS(3_2, 9_0, "Use -[UIViewController prefersStatusBarHidden]") __TVOS_PROHIBITED;

@end

大概的意思呢,就是順着大家的合理思維,蘋果工程師認爲狀態欄是統一共用的,所以控制是統一的,由UIApplication來確定,感覺自己的設計簡直完美。就這樣過了5年,你的青春期消耗殆盡,伴隨着開發者對於這套API的瘋狂吐槽,蘋果工程師們推出了一套由UIViewController來確定狀態欄各種狀態的API,由中央集權制一下子改成了封建制。同時呢,爲了讓大家有一個過度的週期,直到2015年,iOS9的時候,才宣佈UIApplication的這套API廢除。我們來看一下這套新的依附於UIViewController的API。

@interface UIViewController : UIResponder
// Override to return a child view controller or nil. If non-nil, that view controller's status bar appearance attributes will be used. If nil, self is used. Whenever the return values from these methods change, -setNeedsStatusBarAppearanceUpdate should be called.
@property(nonatomic, readonly, nullable) UIViewController *childViewControllerForStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;
@property(nonatomic, readonly, nullable) UIViewController *childViewControllerForStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

@property(nonatomic,assign) BOOL modalPresentationCapturesStatusBarAppearance NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

@property(nonatomic, readonly) UIStatusBarStyle preferredStatusBarStyle NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarStyleDefault
@property(nonatomic, readonly) BOOL prefersStatusBarHidden NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to NO
// Override to return the type of animation that should be used for status bar changes for this view controller. This currently only affects changes to prefersStatusBarHidden.
@property(nonatomic, readonly) UIStatusBarAnimation preferredStatusBarUpdateAnimation NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED; // Defaults to UIStatusBarAnimationFade

// This should be called whenever the return values for the view controller's status bar attributes have changed. If it is called from within an animation block, the changes will be animated along with the rest of the animation block.
- (void)setNeedsStatusBarAppearanceUpdate NS_AVAILABLE_IOS(7_0) __TVOS_PROHIBITED;

@end

那麼相信大家感覺到不妙,彷彿看到了自己隊友寫的代碼,管它現有業務怎麼實現的,自己同時再搞一套,無限Happy。但是,蘋果工程師還是比較有職業操守的,我們只需要在Info.plist中設置View controller-based status bar appearance字段,爲YES呢,則由UIViewController方法自行決定,爲NO呢,則使用UIApplication全局方法決定。毫無疑問,默認值爲YES

也就是這樣,很多新手走上迷茫而又不知所措的道路,感覺狀態欄哇塞,好神奇,該隱藏的時候不隱藏,該出現不出現,很多老項目兩種控制方式的代碼共存,導致新手小弟弟無心工作,心中MMP。下面,出於代碼王的社會責任感,我將給各位小弟弟們耐心的講解一下如何幹死那些你看着不順眼的老油條們,嗯...,不對,是如何完成一個APP狀態欄的控制體系。

從0開始完整搭建狀態欄體系

確定控制方式(中央集權制 & 封建制)

在我們新建項目之前,我們要做一個重大而堅決的決定,決定你的狀態欄的控制方式。上面也有提到,在Info.plist中設置View controller-based status bar appearance字段,爲YES呢,則由UIViewController方法自行決定,爲了後文方便闡述,我們叫它封建制。爲NO呢,則使用UIApplication全局方法決定,同樣的,我們叫它中央集權制。系統默認是封建制

目前很多老項目都存在兩種控制方式代碼並存的情況,請務必永遠不要在項目中珍藏自己的無用或者有可優化控件的代碼!那麼問題來了,你寫的代碼屬於什麼垃圾呢?

API規則分析

無論使用哪種控制方式,無非就是控制顯隱樣式動畫三個方面,API也都很簡單,不做過多贅述。

開局走好第一步

我們創建一個新項目,發現應用啓動的歡迎頁面電池欄默認是存在的,略顯一絲突兀與不和諧,爲了讓用戶有一個良好全面和諧的關注點,那麼我們如何隱藏歡迎頁面的狀態欄呢?這位同學問得好!這個處理方式也很簡單,只需要在Info.plist中添加Status bar is initially hidden,並設置爲YES,就能夠實現一個非常高級的技術點,那就是啓動歡迎頁面隱藏電池欄。

如果你們應用是一個有個性的應用,你也是一個非常有個性的開發,於是,你們決定歡迎頁面要顯示電池欄,這樣會顯得更加的開放與潮流,並且要定製狀態欄的樣式爲UIStatusBarStyleLightContent,那麼你需要在Info.plist中添加Status bar style,並設置爲UIStatusBarStyleLightContent,恭喜你,你已經完成了和產品的靈魂契合。在這裏需要注意一點,如果你選擇中央集權制,那麼這個字段代表了整個項目的默認狀態欄樣式,如果爲封建制,它僅僅代表歡迎頁面的狀態欄樣式。

中央集權制輪轉控制法

首先,表明觀點,無論你們項目現在的控制方式,我不建議再繼續使用這種方式進行迭代。蘋果雖然表示這套API在iOS9之後廢棄,但是並不影響使用,這也是很多項目遲遲不作出調整的原因。這種方式對於多頁面不同狀態的控制有一些不太友好,需要記錄每個頁面的狀態欄特性,並適時的時候利用全局方法進行調整,尤其在一個項目生態中對於新手接受程度是一個考驗。

封建制各國各制控制法

蘋果在iOS7之後推出了這種控制方式,每個頁面自行控制狀態欄的各種狀態,系統會自動根據每個UIViewController的對應方法的返回值進行狀態欄的調整,無需做多餘的控制。例如:

@implementation YSViewController

...
...

- (BOOL)prefersStatusBarHidden {
    return NO;
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

- (UIStatusBarAnimation)preferredStatusBarUpdateAnimation {
    return [super preferredStatusBarUpdateAnimation];
}
@end

表示當這個頁面展示時,顯示狀態欄,使用UIStatusBarStyleLightContent樣式,更新狀態欄時使用默認動畫方式。相對來說,對新手友好度偏高,不至於在歷史原因中迷失了一個初級程序員的天真與無邪。

同樣的,有人會問,如果我在不同的情況下該頁面的狀態欄的狀態是不確定的,甚至是根據用戶的操作實時改變的,使用中央集權制呢,我只需要調用相關方法,直接就能調整爲對應的樣式,那我們使用封建制又該怎麼操作呢?這位同學這個問題問得好!根據蘋果一貫的設計,他想要更新一種可視化的狀態,我覺得他會有類似於setNeedsLayout或者sizeToFit的設計,你覺得呢?看一下新的API,你會發現setNeedsStatusBarAppearanceUpdate,是不是如出一轍呢?那你能聯想到什麼呢?歡迎評論區發表你的觀點和認識。

總結

今天就到這吧,關於狀態欄想說的其實不止於此,我們可以從其中獲取到更爲深刻的東西。不得不說,蘋果整個生態的設計比較穩定,但是如果有大的框架變動,我們在罵街的同時,是不是應該從中獲取到一些別樣的東西去輔助我們對於設計模式更爲深刻的理解呢?作爲一個資深的程序員,如果還在沉醉於+1式的技術積累,你革的是誰的命呢?如果還是習慣性的保留無用或者可優化的代碼,無論不捨或懶惰,那你革的又是誰的命呢?


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章