时隔多多多多多日,突然又又又又又又想写点东西了!写这篇文章呢,主要有两个想法:对于初学的小弟弟们,讲清楚一个知识点的历史走向,梳理顺向的开发流程,做到在项目经理的催活洪流中有条不紊。对于有些经验可做谈资的大哥哥们,可以借鉴苹果系统的设计模式和工作理念,从中吸取完美框架的设计思路。我仅代表伍丽娟祝大家七夕节快乐。
状态栏的发展洪流
咳咳,瓜子准备好了么?如果没有准备好,请到我的微博第一条置顶微博处免费领取,下面请用心的欣赏我的表演。
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式的技术积累,你革的是谁的命呢?如果还是习惯性的保留无用或者可优化的代码,无论不舍或懒惰,那你革的又是谁的命呢?