記 iOS Status Bar 狀態(tài)欄 的一次革命

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

狀態(tài)欄的發(fā)展洪流

咳咳,瓜子準(zhǔn)備好了么?如果沒有準(zhǔn)備好,請到我的微博第一條置頂微博處免費領(lǐng)取,下面請用心的欣賞我的表演。

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

@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

大概的意思呢,就是順著大家的合理思維,蘋果工程師認(rèn)為狀態(tài)欄是統(tǒng)一共用的,所以控制是統(tǒng)一的,由UIApplication來確定,感覺自己的設(shè)計簡直完美。就這樣過了5年,你的青春期消耗殆盡,伴隨著開發(fā)者對于這套API的瘋狂吐槽,蘋果工程師們推出了一套由UIViewController來確定狀態(tài)欄各種狀態(tài)的API,由中央集權(quán)制一下子改成了封建制。同時呢,為了讓大家有一個過度的周期,直到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

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

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

從0開始完整搭建狀態(tài)欄體系

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

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

目前很多老項目都存在兩種控制方式代碼并存的情況,請務(wù)必永遠(yuǎn)不要在項目中珍藏自己的無用或者有可優(yōu)化控件的代碼!那么問題來了,你寫的代碼屬于什么垃圾呢?

API規(guī)則分析

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

開局走好第一步

我們創(chuàng)建一個新項目,發(fā)現(xiàn)應(yīng)用啟動的歡迎頁面電池欄默認(rèn)是存在的,略顯一絲突兀與不和諧,為了讓用戶有一個良好全面和諧的關(guān)注點,那么我們?nèi)绾坞[藏歡迎頁面的狀態(tài)欄呢?這位同學(xué)問得好!這個處理方式也很簡單,只需要在Info.plist中添加Status bar is initially hidden,并設(shè)置為YES,就能夠?qū)崿F(xiàn)一個非常高級的技術(shù)點,那就是啟動歡迎頁面隱藏電池欄。

如果你們應(yīng)用是一個有個性的應(yīng)用,你也是一個非常有個性的開發(fā),于是,你們決定歡迎頁面要顯示電池欄,這樣會顯得更加的開放與潮流,并且要定制狀態(tài)欄的樣式為UIStatusBarStyleLightContent,那么你需要在Info.plist中添加Status bar style,并設(shè)置為UIStatusBarStyleLightContent,恭喜你,你已經(jīng)完成了和產(chǎn)品的靈魂契合。在這里需要注意一點,如果你選擇中央集權(quán)制,那么這個字段代表了整個項目的默認(rèn)狀態(tài)欄樣式,如果為封建制,它僅僅代表歡迎頁面的狀態(tài)欄樣式。

中央集權(quán)制輪轉(zhuǎn)控制法

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

封建制各國各制控制法

蘋果在iOS7之后推出了這種控制方式,每個頁面自行控制狀態(tài)欄的各種狀態(tài),系統(tǒng)會自動根據(jù)每個UIViewController的對應(yīng)方法的返回值進(jìn)行狀態(tài)欄的調(diào)整,無需做多余的控制。例如:

@implementation YSViewController

...
...

- (BOOL)prefersStatusBarHidden {
    return NO;
}

- (UIStatusBarStyle)preferredStatusBarStyle {
    return UIStatusBarStyleLightContent;
}

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

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

同樣的,有人會問,如果我在不同的情況下該頁面的狀態(tài)欄的狀態(tài)是不確定的,甚至是根據(jù)用戶的操作實時改變的,使用中央集權(quán)制呢,我只需要調(diào)用相關(guān)方法,直接就能調(diào)整為對應(yīng)的樣式,那我們使用封建制又該怎么操作呢?這位同學(xué)這個問題問得好!根據(jù)蘋果一貫的設(shè)計,他想要更新一種可視化的狀態(tài),我覺得他會有類似于setNeedsLayout或者sizeToFit的設(shè)計,你覺得呢?看一下新的API,你會發(fā)現(xiàn)setNeedsStatusBarAppearanceUpdate,是不是如出一轍呢?那你能聯(lián)想到什么呢?歡迎評論區(qū)發(fā)表你的觀點和認(rèn)識。

總結(jié)

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


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

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

  • 我們?yōu)槭裁礇]有目標(biāo),沒有目標(biāo)是因為我們沒有內(nèi)在驅(qū)動力,沒有內(nèi)在驅(qū)動力的原因是經(jīng)濟(jì)問題還沒有得到解決,經(jīng)濟(jì)沒有得到解...
    陳俊婷峰硅膠閱讀 291評論 0 0
  • 敬愛的李老師,智慧的班主任,親愛的躍友們大家好: 2019年7月6號我是(管西芹),我的日精進(jìn)行動第357天和大家...
    管西芹閱讀 116評論 0 0
  • 1016第二課 基金的分類 1:按基金投資對象,分為貨幣基金、債券基金、混合基金和股票基金。風(fēng)險由低到高。 2:按...
    愛笑的水晶閱讀 103評論 0 0
  • 春秋多少夢,只在一心間。 躍馬何足道,平常最自然。 (五絕·自然,新韻,戊戌年十一月廿三夜。多少事不由心,多少夢太...
    君子包閱讀 504評論 2 10

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