iOS之頁面布局-踩坑的原由

iOS之頁面布局

原文請點擊

在《iOS 7 UI Transition Guide》中有在《iOS 7 UI Transition Guide》的Bar and Bar Buttons一節中有這么一段話

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中,狀態欄是完全透明的,而其他bar,即navigation bars, tab bars, toolbars, search bars和scope bars都是半透明的。開發者需要保證頁面內容能覆蓋到這些bar的后面。

事實上,iOS7中的狀態欄不僅變完全透明了,而且完全不占空間。
有碼有真相 —— 新建一個UIViewController,再viewDidLoad里面輸入以下代碼,作為rootViewController啟動應用:

- (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];
}

應用效果:

Paste_Image.png

可以看到的是label和status bar悲催地重疊了。
我們再套一個UINavigationController,可以看到更悲催的事情:

Paste_Image.png

label活生生地被navigationBar蓋住了。

可以說,蘋果這次在iOS7上的redesign對開發者來說是慘絕人寰的。
不過蘋果還是有節操的,在iOS7上運行iOS7 SDK以下開發的應用時,保留了原先的頁面結構布局,并且做了不少向下兼容策略。
而且,iOS7 SDK提供了一系列接口和策略方案,下文將會一一介紹并順帶剖析一下iOS7上的頁面結構框架。

Realtime Debug Protal
首先介紹一個小工具,可以方便我們進行學習。它的小名叫RDP,是一個類似Web Inspector的工具,把這個工具引入我們的項目工程,并做一些簡單的配置,然后運行真機或者模擬器。應用啟動后,在瀏覽器輸入手機的IP地址,就可以看到UIView的樹狀結構和Log信息,還可以在瀏覽器中對View進行移動,隱藏,選中高亮等操作。

Paste_Image.png

狀態欄
在iOS7中,狀態欄是透明的,就是說,狀態欄只有文字沒有背景。
而變透明之后就很容易和后面的內容混淆,雖說一般應用不會把內容和狀態欄疊合在一起,但是至少,現在的情況是,默認是會疊合的,開發需要從20px像素以下開始布局頁面元素才能避免。

蘋果為了讓深色淺色背景均能讓狀態欄內容清晰顯示,提供兩種狀態欄樣式:

UIStatusBarStyleDefault = 0 黑色文字,淺色背景時使用
UIStatusBarStyleLightContent = 1 白色文字,深色背景時使用

而以下兩個舊狀態欄樣式將被廢棄:
UIStatusBarStyleBlackTranslucent = 1
UIStatusBarStyleLightContent = 2

還有,iOS7中我們通過ViewController重載方法返回枚舉值的方法來控制狀態欄的隱藏和樣式。
首先,需要在Info.plist配置文件中,增加鍵:UIViewControllerBasedStatusBarAppearance,并設置為YES;
然后,在UIViewController子類中實現以下兩個方法:

- (UIStatusBarStyle)preferredStatusBarStyle
{    return UIStatusBarStyleLightContent;
}- (BOOL)prefersStatusBarHidden
{return NO;
}

最后,在需要刷新狀態欄樣式的時候,調用[self setNeedsStatusBarAppearanceUpdate]方法即可刷新,若果需要以動畫形式切換狀態欄樣式,則用以下方式調用即可:

[UIView animateWithDuration:0. animations:^{[self setNeedsStatusBarAppearanceUpdate];
}];

導航欄
在iOS7,由于狀態欄背景透明,那么,導航欄背景就可能要兼職充當狀態欄背景了。
iOS7默認導航欄樣式就是這么做的,見下圖:

Paste_Image.png

雖然用戶看來,iOS7默認樣式的狀態欄和導航欄時連在一起的,但是實際上導航欄的位置和大小是和之前系統版本一樣的,依然是貼在狀態欄下面, 依然是高44px;之所以用戶看來它們是連在一起,這是因為UINavigationBar里面的_UINavigationBarBackground 定位在y方向-20px的位置,然后高度增加到64px,這樣就可以同時充當了兩者的背景。

關于這些定位,蘋果做了很多工作,后面也會談到不少。不關心的同學可以略過,其實這些細節,個人覺得,即使對于開發者來說,也不是必需知道的,我們只需要知道怎么調用相關API就足夠了。
實際情況下,我們會自定義導航欄背景,過去,我們也許會使用如下代碼把一張高44像素(retina/88像素)的圖片來平鋪作為導航欄背景。

[navCtrl.navigationBar setBackgroundImage:[UIImage imageNamed:@"nav_background"] forBarMetrics:UIBarMetricsDefault];

啟動應用,出現了意想不到的效果和久違的界面 —— 黑底白字的狀態欄,不再被navigationBar蓋住的label。

Paste_Image.png

這里兩個點需要解釋一下:

  1. 若我們使用自定義圖片作為導航欄的背景,那么UIViewController的view(下面稱為視圖)就不會延伸到navigationBar的頂部,而是從它的底部開始——正如往常一樣。
  2. 若我們使用一張高44像素(retina/88像素)的圖片作為導航欄背景,那么狀態欄就會保持黑色,圖片只會在導航欄區域平鋪。

另外,iOS7 SDK中新增了一個設置背景圖片的方法(setBackgroundImage:forBarPosition:barMetrics:),比原有的方法多了一個UIBarPosition枚舉參數,用于設置背景圖片拉伸的策略。
針對不同的拉伸設置和背景圖片尺寸,在《iOS 7 UI Transition Guide》的Bar and Bar Buttons一節中
中有詳細說明:

Paste_Image.png

?

頁面布局
在 《iOS 7 UI Transition Guide》的Layout and Appearance?一節中也提到 —— 在iOS7中,view controllers使用全屏布局 (In iOS 7, view controllers use full-screen layout)。

通過上面的討論我們也知道,除非導航欄設置了自定義的背景圖片,否則每個視圖都會延伸到屏幕一樣大小的。
所以,像上面第二張圖片中出現導航欄遮蓋label的情況也是正常的現象。

如果我們要讓label從導航欄以下位置顯示,可以通過修改UIViewController的edgesForExtendedLayout這個屬性來實現。
edgesForExtendedLayout是一個類型為UIExtendedEdge的屬性,指定邊緣要延伸的方向。
因為iOS7鼓勵全屏布局,它的默認值很自然地是UIRectEdgeAll,四周邊緣均延伸,就是說,如果即使視圖中上有navigationBar,下有tabBar,那么視圖仍會延伸覆蓋到四周的區域。

如果把視圖做如下設置,那么視圖就不會延伸到這些bar的后面了,于是label又出來了。

self.edgesForExtendedLayout = UIExtendedEdgeNone;

Paste_Image.png

也許,這時候你會想,那為什么不把UIExtendedEdgeNone作為默認態呢?
iOS7以后鼓勵全屏,它希望用戶在使用可滾動視圖的時候可以透過半透明的bar還可以看到一些模模糊糊的內容。

為了保持設計的優雅,同時避免給開發者太多的困擾,iOS7在Conttoller中新增了這個屬性:automaticallyAdjustsScrollViewInsets,當設置為YES時(默認YES),如果視圖里面存在唯一一個UIScrollView或其子類View,那么它會自動設置相應的內邊距,這樣可以讓scroll占據整個視圖,又不會讓導航欄遮蓋,如以下例子:

Paste_Image.png

要注意的是,這個例子中我們沒有設置edgesForExtendedLayout,即視圖是延伸至全屏的。
我們可以從UIView樹狀圖看到,tableview的bounds值中有64像素的偏移值,它作為一個內邊距來保持內容顯示在導航欄以下,而滾動時仍可以透過半透明的導航欄看到模糊的內容。

最后一個介紹的新屬性是extendedLayoutIncludesOpaqueBars,這個屬性指定了當Bar使用了不透明圖片時,視圖是否延伸至Bar所在區域,默認值時NO。
所以我們如果自定義了導航欄的背景圖片,那么視圖會從導航欄以下開始,不會延伸到導航欄區域。
如果把這個屬性設置為YES,那么視圖將會延伸至導航欄區域,即使我們把導航欄設置成了自定義背景,如下圖:

Paste_Image.png

視圖延伸之后,label又被導航欄覆蓋住了,正如我們意料。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247507.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247507.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247507.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

工作中的javascript代碼收集及整理

有個pub庫放在blog的文件夾里面了,注意查查1.用javascript去除字符串左右空格,包括全角和半角//用javascript去除字符串左右空格,包括全角和半角String.prototype.trim function() { //其中表示為:對象.屬性.方法函數方法var strTrim this.replace(/(^\s*)|(\s*$)/…

iOS11 更改狀態欄、導航欄顏色的方法

ios上狀態欄 就是指的最上面的20像素高的部分 狀態欄分前后兩部分,要分清這兩個概念,后面會用到: 前景部分:就是指的顯示電池、時間等部分; 背景部分:就是顯示黑色或者圖片的背景部分; (一)設…

i春秋DMZ大型靶場實驗(四)Hash基礎

下載工具包 打開目標機 通過目錄爆破發現 phpmyadmin 在登錄位置嘗試注入 返現 可以注入 直接上sqlmap 上 bp 代理抓包 sqlmap.py -r bp.txt --dbs 利用sqlmap 跑出root 密碼 root666888 登錄 phpmyadmin t通過路徑報錯得到絕對路徑 c:\\www\\1.php root 權限…

解決MAC系統升級導致COCOAPODS失效問題

使用pod install出現如下錯誤 -bash: /usr/local/bin/pod: /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby: bad interpreter: No such file or directory 這是Mac升級系統導致,當你的Mac系統升級為 high siera的時候,別忘記更新…

ASP.NET中進行消息處理(MSMQ) 二

在我上一篇文章《ASP.NET中進行消息處理(MSMQ)一》里對MSMQ做了個通俗的介紹,最后以發送普通文本消息和復雜的對象消息為例介紹了消息隊列的使用。 本文在此基礎上繼續介紹MSMQ的相關知識點,最后還是通過一個示例程序來分析MSMQ在實際項目開發中的應用。…

js常用的數組方法

js常用的數組方法 1.filter() 不會改變原始數組,新數組中的元素是過濾指定數組中符合條件的所有元素 兩種寫法區別:有return 的加了{},否則沒有return不需要加{} var aa [1, 2, 3, 4, 4, 5, 6, 6]; var bb aa.filter((item, index, sel…

iOS 適配HTTPS方法

一切為了迎合蘋果 在WWDC 2016開發者大會上,蘋果宣布了一個最后期限:到2017年1月1日 App Store中的所有應用都必須啟用 App Transport Security安全功能。App Transport Security(ATS)是蘋果在iOS 9中引入的一項隱私保護功能&…

模板—tarjan求割邊

int dfn[MAXN],low[MAXN],cnt; void tarjan(int x,int edg) {low[x]dfn[x]cnt;for(int if(x);i;in(i))if(!dfn[v(i)]){tarjan(v(i),i);low[x]min(low[x],low[v(i)]);if(low[v(i)]>dfn[x])isbridge[i]isbridge[i^1]1;}else if(i!(edg^1))low[x]min(low[x],dfn(v(i))); } 轉載…

GoJs Pictures 官方介紹文檔

圖片 使用Picture類顯示圖像。 最常見的用法是使用URL字符串設置Picture.source屬性,以及通過GraphObject.desiredSize(圖對象的所需尺寸)獲取或通過設置GraphObject.width(圖對象的寬)和GraphObject.height&#xff0…

怎樣購買及安裝ssl安全證書

查找資料記錄,不是我的項目筆記 現在越來越多的網站都開始用安全鏈接了,在國外的話,如果不是一個安全鏈接,用戶很大程度上會拒絕使用,所有安全鏈接是未來的趨勢,樓主第一次配安全證書的時候,剛剛…

XmlViewResolver 和 ResourceBundleViewResolver

使用XmlViewResolver 如果視圖對象的 Bean 數目太多,那么直接在 smart-servlet.xml 文件中配置,勢必影響主配置文件的簡潔性。XmlViewResolver 和 BeanNameViewResolver 功能相似,唯一不同的是它可以將視圖 Bean 定義在一個獨立的 XML 文件中…

(轉載)Git使用教程:最詳細、最傻瓜、最淺顯、真正手把手教!

轉載自 Git使用教程 預警:因為詳細,所以行文有些長,新手邊看邊操作效果出乎你的預料)一:Git是什么? Git是目前世界上最先進的分布式版本控制系統。 工作原理 / 流程: Workspace:工作…

soureTree中如何設置git 用戶名與密碼 SourceTree提交修改用戶詳細圖文方法

mac上軟件更新: 現在沒有網絡小模塊了,在同行右邊高級里面有默認用戶名刪除即可!!!! sourceTree 切換Git登錄用戶,之前在SourceTree提交遠程服務用的是同事的賬號,同事離職后賬號也…

shell 腳本 生成文件,文件名為日期時間

腳本如下 #/bin/bashfilename$(date %Y%m%d)_$(date %H%M%S) touch $filename.txt 其中 $() 表示括號中的 shell 命令的結果,所以 filename 是一個字符串,比如 20190714_111631,即 2019 年 7 月 14 日 11 點 16 分 31 秒。 然后第二行命令&am…

js利用HTML5的拖拽API做流程圖

上代碼 直接用看效果&#xff0c;學習一下 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Document</title><style type"text/css">#d1{width:800px;height:800px;border: 1…

Pots (BFS ? 輸出路徑)

題目鏈接&#xff1a;http://poj.org/problem?id3414 思路&#xff1a; 因為有六種操作&#xff0c;所以六種操作中合法的都加入隊列中BFS 如何去輸出路徑呢&#xff1f; 我們不妨設一個string數組&#xff0c;它的索引就和我們的步數有關&#xff0c;然后按順序輸出就可以了…

box-sizing的使用

box-sizing 人們慢慢的意識到傳統的盒子模型不直接&#xff0c;所以他們新增了一個叫做 box-sizing 的CSS屬性。當你設置一個元素為 box-sizing: border-box; 時&#xff0c;此元素的內邊距和邊框不再會增加它的寬度。這里有一個與前一頁相同的例子&#xff0c;唯一的區別是兩…

vue-router的hash模式和history模式,

hash模式背后的原理是onhashchange事件,可以在window對象上監聽這個事件: window.onhashchange function(event){ console.log(event.oldURL, event.newURL); let hash location.hash.slice(1); document.body.style.color hash; } 上面的代碼可以通過改變hash來改變頁面字體…

更新node最新版本方法和 npm install -g n 運行錯誤

使用xshell連接linux服務器后&#xff0c;首先輸入node -v查看當前使用的版本 如果上面查看的版本比較低&#xff0c;則可以開始升級 清除npm cache 升級之前還需要安裝n模塊&#xff0c;n模塊是專門用來管理nodejs的版本 輸入npm install -g n n模塊安裝完成之后&#x…