在《iOS 7 UI Transition Guide》中有在《iOS 7 UI Transition Guide》的Bar and Bar Buttons一節(jié)中有這么一段話
In iOS 7, the status bar is transparent, and other bars—that is, navigation bars, tab bars, toolbars, search bars, and scope bars—are translucent. As a general rule, you want to make sure that content fills the area behind the bars in your app.
翻譯過來:
在iOS7中娇昙,狀態(tài)欄是完全透明的冒掌,而其他bar蹲盘,即navigation bars, tab bars, toolbars, search bars和scope bars都是半透明的。開發(fā)者需要保證頁(yè)面內(nèi)容能覆蓋到這些bar的后面铃诬。
事實(shí)上苍凛,iOS7中的狀態(tài)欄不僅變完全透明了,而且完全不占空間宣肚。
有碼有真相 —— 新建一個(gè)UIViewController悠栓,再viewDidLoad里面輸入以下代碼按价,作為rootViewController啟動(dòng)應(yīng)用:
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
UILabel *label = [[[UILabel alloc]initWithFrame:CGRectMake(0, 0, 200, 20)]autorelease];
label.text = @"I am a label";
[self.view addSubview:label];
}
應(yīng)用效果:
可以看到的是label和status bar悲催地重疊了楼镐。
我們?cè)偬滓粋€(gè)UINavigationController逮走,可以看到更悲催的事情:
label活生生地被navigationBar蓋住了。
可以說茅信,蘋果這次在iOS7上的redesign對(duì)開發(fā)者來說是慘絕人寰的墓臭。
不過蘋果還是有節(jié)操的,在iOS7上運(yùn)行iOS7 SDK以下開發(fā)的應(yīng)用時(shí)酌摇,保留了原先的頁(yè)面結(jié)構(gòu)布局嗡载,并且做了不少向下兼容策略。
而且埂息,iOS7 SDK提供了一系列接口和策略方案遥巴,下文將會(huì)一一介紹并順帶剖析一下iOS7上的頁(yè)面結(jié)構(gòu)框架。
Realtime Debug Protal
首先介紹一個(gè)小工具拾弃,可以方便我們進(jìn)行學(xué)習(xí)摆霉。它的小名叫RDP,是一個(gè)類似Web Inspector的工具搭盾,把這個(gè)工具引入我們的項(xiàng)目工程刻两,并做一些簡(jiǎn)單的配置滴某,然后運(yùn)行真機(jī)或者模擬器。應(yīng)用啟動(dòng)后户誓,在瀏覽器輸入手機(jī)的IP地址,就可以看到UIView的樹狀結(jié)構(gòu)和Log信息碍彭,還可以在瀏覽器中對(duì)View進(jìn)行移動(dòng)悼潭,隱藏,選中高亮等操作皆疹。
狀態(tài)欄
在iOS7中占拍,狀態(tài)欄是透明的晃酒,就是說,狀態(tài)欄只有文字沒有背景贝次。
而變透明之后就很容易和后面的內(nèi)容混淆浊闪,雖說一般應(yīng)用不會(huì)把內(nèi)容和狀態(tài)欄疊合在一起,但是至少搁宾,現(xiàn)在的情況是盖腿,默認(rèn)是會(huì)疊合的,開發(fā)需要從20px像素以下開始布局頁(yè)面元素才能避免翩腐。
蘋果為了讓深色淺色背景均能讓狀態(tài)欄內(nèi)容清晰顯示茂卦,提供兩種狀態(tài)欄樣式:
UIStatusBarStyleDefault = 0 黑色文字,淺色背景時(shí)使用
UIStatusBarStyleLightContent = 1 白色文字等龙,深色背景時(shí)使用
而以下兩個(gè)舊狀態(tài)欄樣式將被廢棄:
UIStatusBarStyleBlackTranslucent = 1
UIStatusBarStyleLightContent = 2
還有,iOS7中我們通過ViewController重載方法返回枚舉值的方法來控制狀態(tài)欄的隱藏和樣式罐栈。
首先,需要在Info.plist配置文件中琅翻,增加鍵:UIViewControllerBasedStatusBarAppearance柑贞,并設(shè)置為YES钧嘶;
然后,在UIViewController子類中實(shí)現(xiàn)以下兩個(gè)方法:
- (UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
- (BOOL)prefersStatusBarHidden
{
return NO;
}
最后摄欲,在需要刷新狀態(tài)欄樣式的時(shí)候疮薇,調(diào)用[self setNeedsStatusBarAppearanceUpdate]方法即可刷新,若果需要以動(dòng)畫形式切換狀態(tài)欄樣式按咒,則用以下方式調(diào)用即可:
[UIView animateWithDuration:0. animations:^{
[self setNeedsStatusBarAppearanceUpdate];
}];
導(dǎo)航欄
在iOS7励七,由于狀態(tài)欄背景透明,那么吼野,導(dǎo)航欄背景就可能要兼職充當(dāng)狀態(tài)欄背景了两波。
iOS7默認(rèn)導(dǎo)航欄樣式就是這么做的单起,見下圖:
雖然用戶看來劣坊,iOS7默認(rèn)樣式的狀態(tài)欄和導(dǎo)航欄時(shí)連在一起的,但是實(shí)際上導(dǎo)航欄的位置和大小是和之前系統(tǒng)版本一樣的测蘑,依然是貼在狀態(tài)欄下面, 依然是高44px;之所以用戶看來它們是連在一起固逗,這是因?yàn)閁INavigationBar里面的_UINavigationBarBackground 定位在y方向-20px的位置藕帜,然后高度增加到64px,這樣就可以同時(shí)充當(dāng)了兩者的背景贝攒。
關(guān)于這些定位时甚,蘋果做了很多工作,后面也會(huì)談到不少梨熙。不關(guān)心的同學(xué)可以略過刀诬,其實(shí)這些細(xì)節(jié),個(gè)人覺得质欲,即使對(duì)于開發(fā)者來說糠馆,也不是必需知道的,我們只需要知道怎么調(diào)用相關(guān)API就足夠了奋早。
實(shí)際情況下赠橙,我們會(huì)自定義導(dǎo)航欄背景,過去掉奄,我們也許會(huì)使用如下代碼把一張高44像素(retina/88像素)的圖片來平鋪?zhàn)鳛閷?dǎo)航欄背景。
[navCtrl.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav_background"] forBarMetrics:UIBarMetricsDefault];
啟動(dòng)應(yīng)用诞仓,出現(xiàn)了意想不到的效果和久違的界面 —— 黑底白字的狀態(tài)欄速兔,不再被navigationBar蓋住的label。
這里兩個(gè)點(diǎn)需要解釋一下:
- 若我們使用自定義圖片作為導(dǎo)航欄的背景谍婉,那么UIViewController的view(下面稱為視圖)就不會(huì)延伸到navigationBar的頂部镀钓,而是從它的底部開始——正如往常一樣。
- 若我們使用一張高44像素(retina/88像素)的圖片作為導(dǎo)航欄背景丁溅,那么狀態(tài)欄就會(huì)保持黑色,圖片只會(huì)在導(dǎo)航欄區(qū)域平鋪妓柜。
另外涯穷,iOS7 SDK中新增了一個(gè)設(shè)置背景圖片的方法(setBackgroundImage:forBarPosition:barMetrics:)求豫,比原有的方法多了一個(gè)UIBarPosition枚舉參數(shù),用于設(shè)置背景圖片拉伸的策略最疆。
針對(duì)不同的拉伸設(shè)置和背景圖片尺寸蚤告,在《iOS 7 UI Transition Guide》的Bar and Bar Buttons一節(jié)中
中有詳細(xì)說明:
頁(yè)面布局
在 《iOS 7 UI Transition Guide》的Layout and Appearance 一節(jié)中也提到 —— 在iOS7中杜恰,view controllers使用全屏布局 (In iOS 7, view controllers use full-screen layout)。
通過上面的討論我們也知道心褐,除非導(dǎo)航欄設(shè)置了自定義的背景圖片逗爹,否則每個(gè)視圖都會(huì)延伸到屏幕一樣大小的。
所以,像上面第二張圖片中出現(xiàn)導(dǎo)航欄遮蓋label的情況也是正常的現(xiàn)象于购。
如果我們要讓label從導(dǎo)航欄以下位置顯示知染,可以通過修改UIViewController的edgesForExtendedLayout這個(gè)屬性來實(shí)現(xiàn)控淡。
edgesForExtendedLayout是一個(gè)類型為UIExtendedEdge的屬性,指定邊緣要延伸的方向逸寓。
因?yàn)閕OS7鼓勵(lì)全屏布局竹伸,它的默認(rèn)值很自然地是UIRectEdgeAll簇宽,四周邊緣均延伸,就是說譬嚣,如果即使視圖中上有navigationBar钞它,下有tabBar,那么視圖仍會(huì)延伸覆蓋到四周的區(qū)域尼桶。
如果把視圖做如下設(shè)置锯仪,那么視圖就不會(huì)延伸到這些bar的后面了,于是label又出來了小腊。
self.edgesForExtendedLayout = UIExtendedEdgeNone;
也許秩冈,這時(shí)候你會(huì)想斥扛,那為什么不把UIExtendedEdgeNone作為默認(rèn)態(tài)呢?
iOS7以后鼓勵(lì)全屏队他,它希望用戶在使用可滾動(dòng)視圖的時(shí)候可以透過半透明的bar還可以看到一些模模糊糊的內(nèi)容。
為了保持設(shè)計(jì)的優(yōu)雅锡凝,同時(shí)避免給開發(fā)者太多的困擾垢啼,iOS7在Conttoller中新增了這個(gè)屬性:automaticallyAdjustsScrollViewInsets,當(dāng)設(shè)置為YES時(shí)(默認(rèn)YES)锚扎,如果視圖里面存在唯一一個(gè)UIScrollView或其子類View馁启,那么它會(huì)自動(dòng)設(shè)置相應(yīng)的內(nèi)邊距,這樣可以讓scroll占據(jù)整個(gè)視圖翠勉,又不會(huì)讓導(dǎo)航欄遮蓋霉颠,如以下例子:
要注意的是蒿偎,這個(gè)例子中我們沒有設(shè)置edgesForExtendedLayout,即視圖是延伸至全屏的华坦。
我們可以從UIView樹狀圖看到不从,tableview的bounds值中有64像素的偏移值,它作為一個(gè)內(nèi)邊距來保持內(nèi)容顯示在導(dǎo)航欄以下歹袁,而滾動(dòng)時(shí)仍可以透過半透明的導(dǎo)航欄看到模糊的內(nèi)容寝优。
最后一個(gè)介紹的新屬性是extendedLayoutIncludesOpaqueBars,這個(gè)屬性指定了當(dāng)Bar使用了不透明圖片時(shí)孟抗,視圖是否延伸至Bar所在區(qū)域,默認(rèn)值時(shí)NO铅协。
所以我們?nèi)绻远x了導(dǎo)航欄的背景圖片摊沉,那么視圖會(huì)從導(dǎo)航欄以下開始说墨,不會(huì)延伸到導(dǎo)航欄區(qū)域。
如果把這個(gè)屬性設(shè)置為YES尼斧,那么視圖將會(huì)延伸至導(dǎo)航欄區(qū)域棺棵,即使我們把導(dǎo)航欄設(shè)置成了自定義背景楼咳,如下圖:
視圖延伸之后,label又被導(dǎo)航欄覆蓋住了律秃,正如我們意料爬橡。