原文網(wǎng)址:http://www.cocoachina.com/industry/20131203/7462.html
原文:Beginning Auto Layout Tutorial in iOS 7: Part 1
感謝翻譯小組成員@answer-huang(博客)熱心翻譯。如果您有不錯(cuò)的原創(chuàng)或譯文,歡迎提交給我們,更歡迎其他朋友加入我們的翻譯小組(聯(lián)系qq:2408167315)。
==========================================================================
提示:團(tuán)隊(duì)成員Jatthijs Hollemans(iOS 初級(jí)系列作者)已經(jīng)將這篇文章移植到iOS7 feast上。希望你能夠喜歡。
你是否曾經(jīng)想讓你的app在橫豎屏方向上看起來(lái)都表現(xiàn)良好而受挫?是否在做支持iPhone和iPad屏幕布局界面時(shí)幾近大小便失禁?今天我將給你帶來(lái)好消息! 一直為大小相同的屏幕設(shè)計(jì)一個(gè)用戶界面并不難,但如果屏幕的尺寸改變的話,UI元素的位置和大小也需要相應(yīng)的做出改變。 到目前為止,如果你的設(shè)計(jì)相當(dāng)?shù)膹?fù)雜,那么你必須編寫(xiě)大量的代碼來(lái)適應(yīng)這樣的布局。你應(yīng)該很高興,現(xiàn)在這樣的情況再也不存在了--iOS6為iPhone和iPad帶來(lái)了一個(gè)極好的新特性:自動(dòng)布局。Xcode 5和 iOS7中對(duì)自動(dòng)布局做出了改善!如果你曾經(jīng)嘗試著在Xcode4中使用自動(dòng)布局并最終做出放棄,現(xiàn)在是該給Xcode5一次機(jī)會(huì)了。 在你的程序中,自動(dòng)布局不僅可以很容易的支持不同大小的屏幕,一個(gè)額外的功能,它也使得本地化幾乎變得微不足道。你不再需要為每種你希望支持的語(yǔ)言創(chuàng)建新的nibs或storyboards,包括像Hebrew或Arabic這樣從右到左的語(yǔ)言。 這個(gè)教程將向你展示如何使用Interface Builder開(kāi)始自動(dòng)布局.在iOS6 教程中,我們進(jìn)一步討論過(guò)這個(gè)教程,然后有一個(gè)基于這個(gè)知識(shí)點(diǎn)完整的新章節(jié),并且向你展示如何通過(guò)代碼完全釋放出自動(dòng)布局的能量。 注意:我們已經(jīng)開(kāi)始將iOS6教程中相應(yīng)的章節(jié)更新到iOS7-這只是先給大家解解饞!當(dāng)我們完成后,所有iOS6 PDF教程的訂閱者將會(huì)得到免費(fèi)的更新下載。 so,備好零食和你喜歡的咖啡,準(zhǔn)備成為自動(dòng)布局的達(dá)人吧!
springs和struts的問(wèn)題 你肯定很熟悉autosizing masks-也被認(rèn)為是springs&struts模式。autosizing mask決定了當(dāng)一個(gè)視圖的父視圖大小改變時(shí),其自身需要做出什么改變。它有一個(gè)靈活的或固定不變的margins(struts)嗎?它的寬和高要做出什么改變(springs)? 舉個(gè)例子,一個(gè)寬度靈活的視圖,如果其父視圖邊框,那么它也會(huì)相應(yīng)的變寬。一個(gè)視圖右邊擁有固定的margin,那么它的右邊緣將會(huì)一直粘住其父視圖的右邊緣。 autosizing系統(tǒng)在簡(jiǎn)單的情況下非常奏效,但當(dāng)你布局變得更復(fù)雜時(shí),它立馬跪了。讓我們看一個(gè)springs和struts不能處理的示例。 打開(kāi)Xcode5,創(chuàng)建一個(gè)基于Single View Application模板的iPhone項(xiàng)目。叫做"StrutsProblem": 點(diǎn)擊Main.storyboard。在你做別的之前,首先將這個(gè)storyboard的自動(dòng)布局關(guān)了。你需要在File inspector,第一個(gè)選項(xiàng)的第六個(gè)tabs里: 將Use Autolayout的box勾選去掉。現(xiàn)在storyboard使用舊的struts-and-springs模型。 注意:任何你使用Xcode4.5或更高版本中,nib或者storyboard文件都默認(rèn)激活了自動(dòng)布局。因?yàn)樽詣?dòng)布局是iOS6以及以上系統(tǒng)的一個(gè)新特性,如果你想使用最新的Xcode開(kāi)發(fā)兼容iOS5的程序,你需要將這個(gè)選項(xiàng)去掉。 拖拽三個(gè)新的視圖到主視圖上,并且像這樣排列起來(lái): 為了表述更清楚,這里給出每個(gè)視圖的顏色,這樣你就能分清哪個(gè)是驢子哪個(gè)是馬了。 每個(gè)視圖的inset到窗口的距離都是20點(diǎn);視圖之間的距離也是20點(diǎn)。底部的視圖的寬是280點(diǎn),上面兩個(gè)視圖的寬都是130點(diǎn)。所有的視圖的高都是254。 在iPhone Retina 4-inch simulator上運(yùn)行這個(gè)程序,并且將模擬器旋轉(zhuǎn)到landscape。程序看起來(lái)便變成這副鬼樣,這不是我想象的那樣: 注意:你可以使用Hardware\Rotate Left和Rotate Right菜單選項(xiàng)旋轉(zhuǎn)模擬器,或者通過(guò)按下鍵盤上的??鍵,同時(shí)按下←或→。 而你想象的程序在landscape應(yīng)該像這樣: 很明顯,三個(gè)視圖的autosizing masks留下了一些需要改進(jìn)的地方。將左上方視圖的autosizing設(shè)置改成這樣: 這將會(huì)讓視圖貼附左上邊緣(不是右下邊緣),并且當(dāng)父視圖大小改變時(shí),重新調(diào)整自身水平和垂直方向的大小。 同樣的,右上方視圖的autosizing設(shè)置改成這樣: 底部視圖: 再次運(yùn)行程序,并且旋轉(zhuǎn)到landscape。現(xiàn)在看起來(lái)像這樣: 已經(jīng)很接近了,但又不完全一樣。視圖之間的padding不正確。換個(gè)說(shuō)法就是視圖的大小不完全正確。問(wèn)題出在當(dāng)父視圖改變大小時(shí),autosizing masks告訴子視圖調(diào)整大小,但又沒(méi)告訴子視圖該調(diào)整多少(坑兒?)。 你可以調(diào)戲autosizing masks-比如,改變靈活寬度和高度設(shè)置(springs)-你不會(huì)得到完全正確的三個(gè)間距20點(diǎn)的視圖。 為了解決這個(gè)springs和struts方法的布局問(wèn)題,非常不幸,你需要額外寫(xiě)一些代碼。 在旋轉(zhuǎn)用戶界面之前、之間、之后,UIKit會(huì)發(fā)送一些消息到你的視圖控制器,你可以截獲這些消息,從而對(duì)你UI做出改變。代表性的像viewWillLayoutSubviews,你會(huì)重寫(xiě)這個(gè)方法從而改變?nèi)魏涡枰匦屡帕械囊晥D的frame。 在這之前,你需要先做出一個(gè)outlet屬性來(lái)引用這個(gè)視圖。 切換到Assistant Editor模式,按住Ctrl,將三個(gè)視圖都拖到ViewController.m中去: 分別鏈接視圖到這三個(gè)屬性:
@property?(weak,?nonatomic)?IBOutlet?UIView?*topLeftView;?@property?(weak,?nonatomic)?IBOutlet?UIView?*topRightView;?@property?(weak,?nonatomic)?IBOutlet?UIView?*bottomView;? 下面的代碼寫(xiě)到ViewController.m:
-?(void)viewWillLayoutSubviews?{?????if?(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))?????{?????????CGRect?rect?=?self.topLeftView.frame;?????????rect.size.width?=?254;?????????rect.size.height?=?130;?????????self.topLeftView.frame?=?rect;???????????rect?=?self.topRightView.frame;?????????rect.origin.x?=?294;?????????rect.size.width?=?254;?????????rect.size.height?=?130;?????????self.topRightView.frame?=?rect;???????????rect?=?self.bottomView.frame;?????????rect.origin.y?=?170;?????????rect.size.width?=?528;?????????rect.size.height?=?130;?????????self.bottomView.frame?=?rect;?????}?????else?????{?????????CGRect?rect?=?self.topLeftView.frame;?????????rect.size.width?=?130;?????????rect.size.height?=?254;?????????self.topLeftView.frame?=?rect;???????????rect?=?self.topRightView.frame;?????????rect.origin.x?=?170;?????????rect.size.width?=?130;?????????rect.size.height?=?254;?????????self.topRightView.frame?=?rect;???????????rect?=?self.bottomView.frame;?????????rect.origin.y?=?295;?????????rect.size.width?=?280;?????????rect.size.height?=?254;?????????self.bottomView.frame?=?rect;?????}?}?當(dāng)視圖控制器旋轉(zhuǎn)到一個(gè)新的方向,這個(gè)回調(diào)將會(huì)被調(diào)用。它會(huì)監(jiān)控視圖控制器旋轉(zhuǎn)的方向,并且適當(dāng)?shù)恼{(diào)整視圖大小-在這種情況,根據(jù)已知iPhone屏幕大小會(huì)有一個(gè)hard-code(將可變變量用一個(gè)固定值來(lái)代替的方法叫做hard-code)偏移。這個(gè)回調(diào)會(huì)在一個(gè)動(dòng)畫(huà)block中發(fā)生,所以會(huì)動(dòng)態(tài)的改變大小。 暫時(shí)還不要運(yùn)行這個(gè)程序。首先你需要按下面的樣子重新保存三個(gè)視圖的autosizing masks,否則autosizing mechanism將會(huì)和你在viewWillLayoutSubviews中設(shè)置的位置和大小沖突。 這樣就可以了,運(yùn)行程序并且翻轉(zhuǎn)到landscape。現(xiàn)在視圖排列的非常號(hào)。翻轉(zhuǎn)回到portrait,經(jīng)核實(shí),一切都良好。 這樣奏效了,但是你需要為這個(gè)非常簡(jiǎn)單的例子編寫(xiě)大量的布局代碼。想象一下,為布局付出的努力是非常復(fù)雜的,特別是個(gè)別視圖動(dòng)態(tài)的改變大小,或者子視圖的個(gè)數(shù)是不固定的。 現(xiàn)在試著在3.5寸的模擬器上運(yùn)行程序。我了個(gè)去。視圖的位置和大小又錯(cuò)了,因?yàn)関iewWillLayoutSubviews的hard-code坐標(biāo)是基于4英寸大小的手機(jī)(320x568取代320x480)。你可以增加另一個(gè)if語(yǔ)句判斷屏幕大小,并使用不同的坐標(biāo)集,但是你可以看到這個(gè)方法很快變得不切實(shí)際。
注意:另一個(gè)你可以采取的方法就是為portrait和landscape模式建立獨(dú)立的nibs。當(dāng)設(shè)備旋轉(zhuǎn)時(shí),你從另一個(gè)nib中裝載視圖并替換掉當(dāng)前的那個(gè)。但這任然需要做很多工作,并且維護(hù)兩個(gè)nibs也會(huì)增加問(wèn)題。當(dāng)你使用storyboards替代nibs的時(shí)候,這個(gè)方法也變得不切實(shí)際。
自動(dòng)布局拯救猿! 現(xiàn)在你將會(huì)看到如何用自動(dòng)布局實(shí)現(xiàn)相同的效果,從ViewController.m中移除viewWillLayoutSubviews,因?yàn)槲覀儾辉傩枰獙?xiě)任何代碼。 選擇Main.storyboard,并在File inspector中選擇開(kāi)啟Use Autolayout: 運(yùn)行程序,旋轉(zhuǎn)到landscape。現(xiàn)在看起來(lái)像這樣: 讓我們把自動(dòng)布局付諸行動(dòng)。當(dāng)你點(diǎn)擊頂部?jī)蓚€(gè)視圖時(shí),按住?鍵,這樣兩個(gè)視圖都被選中了。從Xcode的Editor菜單中選擇Pin\Widths Equally: 再次選中兩個(gè)相同的視圖,選擇Editor\Pin\Horizontal Spacing。(盡管你執(zhí)行完第一次Pin處理后,兩個(gè)視圖看起來(lái)還是被選中的,但其實(shí)他們只是在一個(gè)特別的布局關(guān)系顯示模型里。所以你需要重新選擇這兩個(gè)視圖) storyboard現(xiàn)在看起來(lái)像這樣: 橙色的"T-bar"形狀代表視圖間的約束。目前為止你增加了兩個(gè)約束:一個(gè)等寬約束和一個(gè)位于兩個(gè)視圖間的水平約束。約束表達(dá)了視圖之間的關(guān)系,并且他們是你使用自動(dòng)布局建立布局最主要的工具。這貨看起來(lái)有點(diǎn)嚇人,但是一旦弄懂它的意思,便變得相當(dāng)簡(jiǎn)單。 為了繼續(xù)為這個(gè)屏幕簡(jiǎn)歷布局,執(zhí)行下面這些步驟。每個(gè)步驟增加更多橘黃色的T-bars.
o Top Space to Superview o Leading Space to Superview For the view on the right, choose:
o Top Space to Superview o Trailing Space to Superview And for the big view at the bottom:
o Leading Space to Superview o Trailing Space to Superview o Bottom Space to Superview 現(xiàn)在你應(yīng)該有了下面這些約束:
注意T-bars仍然是橘黃色的。這意味這你的布局沒(méi)有完成;自動(dòng)布局沒(méi)有足夠的約束條件計(jì)算出視圖的位置和大小。解決辦法便是增加更多約束,直到他們變藍(lán)。 按下??鍵并選中三個(gè)視圖。從Editor菜單中,選擇Pin\Heights Equally。 現(xiàn)在選中左上角的視圖和底部視圖(像前面一樣按住??鍵),選擇Editor\Pin\Vertical Spacing. Interface Builder看起來(lái)應(yīng)該像這樣: T-bars已經(jīng)變藍(lán)了。自動(dòng)布局現(xiàn)在已經(jīng)有足夠的信息來(lái)計(jì)算出一個(gè)有效的布局。這看起來(lái)有點(diǎn)雜亂無(wú)章,這是因?yàn)榈葘捄偷雀呒s束條件占去了很大空間。 運(yùn)行程序并且...我說(shuō)吧,不需要寫(xiě)一行代碼便運(yùn)行的很好了。不管你在哪個(gè)模擬器上運(yùn)行;在3.5英寸和4英寸設(shè)備上,布局都運(yùn)行良好。 這非常酷,但是究竟你在這做了什么?自動(dòng)布局讓你表達(dá)出布局中的視圖和其他每個(gè)視圖的關(guān)系,而不是需要你指出視圖有多大,放在哪兒。你需要放置以下這些關(guān)系(即我們所謂的約束)到布局中: 1.左上角和右上角的視圖總是有相等的寬度(也就是pin中第一個(gè)widths equally命令)。 2.左上角和右上角的視圖水平方向有20點(diǎn)距離(也就是pin中的horizontal spacing)。 3.所有的視圖總是有相同的高度(也就是pin中heights equally命令)。 4.上面兩個(gè)視圖和下面那個(gè)視圖垂直方向上有20點(diǎn)距離(也就是pin中的vertical spacing)。 5.視圖和屏幕邊緣有20點(diǎn)空間(top,bottom,leading和trailing space相對(duì)于父視圖的約束)。 這些就足以表達(dá)出自動(dòng)布局該怎么放置視圖,以及當(dāng)屏幕大小改變時(shí)該如何處理。 你可以在左邊Document Outline中看到你所有的約束,組名叫做Constraints(當(dāng)你為storyboard激活自動(dòng)布局時(shí)才會(huì)加進(jìn)來(lái))。 如果你在Document Outline中點(diǎn)擊一個(gè)約束,Interface Builder將會(huì)在視圖中高亮出它: 約束是一個(gè)真實(shí)的對(duì)象(NSLayoutConstraint),并且他們也有屬性。比如,選擇上面兩個(gè)視圖的間距約束條件(叫做"Horizontal Space(20)"),然后切換到Attributes inspector。你可以在那里通過(guò)編輯Constant字段改變邊緣空間的大小。 將它設(shè)置為100,然后再次運(yùn)行程序。現(xiàn)在他們邊緣空間變得更寬了: 自動(dòng)布局在描述視圖上比springs和struts顯得更有表現(xiàn)力。在這篇教程的剩余部分,你將會(huì)學(xué)到約束的一切,以及如何將他們應(yīng)用到Interface Builder上來(lái)構(gòu)造出不同種類的布局。
自動(dòng)布局如何工作 正如你在上面測(cè)試樣例中所看到的一樣,自動(dòng)布局最基本的工具是約束。一個(gè)約束描述了兩個(gè)視圖間的幾何關(guān)系。比如,你可能有這樣一個(gè)約束: "label A右邊緣和button B左邊緣有20點(diǎn)的空白空間。" 自動(dòng)布局會(huì)考慮到所有的約束,然后為你的視圖計(jì)算出理想的位置和大小。你再也不需要親自為你的視圖設(shè)置frames了-自動(dòng)布局會(huì)完全基于你為這些視圖設(shè)置的約束為你做這個(gè)工作。 自動(dòng)布局以前,你一直需要為視圖的frames設(shè)置hard-code,要么在Interface Builder中將他們放置在特定的坐標(biāo),或通過(guò)傳遞一個(gè)rectangle到initWithFrame:,或者設(shè)置視圖的frame,bounds或者center屬性。 就你剛剛做的那個(gè)程序,你需要明確設(shè)置frames為: 還需要為這些視圖設(shè)置自動(dòng)調(diào)整大小的masks: 這再也不是你需要為屏幕設(shè)計(jì)所考慮的東西了。使用自動(dòng)布局,你需要做這些: 視圖的大小和位置再也不重要了,只有約束要緊。當(dāng)然,當(dāng)你拖一個(gè)新建的button或label到畫(huà)布上時(shí),它會(huì)有一定的大小,并且你會(huì)將它拖到某一位置,但這是只一個(gè)用來(lái)告訴Interface Builder如何放置約束的設(shè)計(jì)工具。
想你所想,如你所愿 使用約束最大的優(yōu)勢(shì)就是你再也不需要把時(shí)間浪費(fèi)在坐標(biāo)上了。相反,你可以向自動(dòng)布局描述視圖如何和其他視圖相關(guān)聯(lián),自動(dòng)布局將會(huì)為你完成所有困難的工作。這叫做根據(jù)目的設(shè)計(jì)(designing by intent)。 當(dāng)你根據(jù)目的設(shè)計(jì)時(shí),你表達(dá)的是你想要實(shí)現(xiàn)什么,而不需要關(guān)心它如何實(shí)現(xiàn)。"button的左上角坐標(biāo)為(20,230)",現(xiàn)在你可以這么說(shuō)了:button是垂直居中于它的父視圖,并且相對(duì)于父視圖的左邊緣有一個(gè)固定的距離。 使用這個(gè)描述,不管父視圖多大或多小,自動(dòng)布局都可以自動(dòng)計(jì)算出你的button需要在哪兒出現(xiàn), 其他根據(jù)目的設(shè)計(jì)的示例(自動(dòng)布局可以處理所有這些指令): "這兩個(gè)text fields的大小需要一直相等。" "這兩個(gè)button需要一直一起移動(dòng)。" "這四個(gè)labels需要一直右對(duì)齊。" 這使得你用戶界面的設(shè)置更具描述性。你只需簡(jiǎn)單的定義約束,系統(tǒng)會(huì)為你自動(dòng)計(jì)算frames。 在第一部分你看到,即使為幾個(gè)視圖在橫豎方向上正確的布局都需要做大量的工作。有了自動(dòng)布局,你可以繞過(guò)這些麻煩。如果你正確的設(shè)置了約束,那么在橫豎屏方向上,布局將不需要做任何改變。 使用自動(dòng)布局另一個(gè)重要的好處就是本地化。比如德語(yǔ)中的文本,出了名的比老奶奶的裹腳布還要長(zhǎng),適配起來(lái)是一件很麻煩的事。再次,自動(dòng)布局拯救了猿,因?yàn)樗芨鶕?jù)label需要顯示的內(nèi)容自動(dòng)改變label的大小。 現(xiàn)在增加德語(yǔ),法語(yǔ)或者其他任何一種語(yǔ)言,都只是設(shè)置約束的事,然后翻譯文本,然后。。。就沒(méi)有然后了! 獲得自動(dòng)布局竅門最好的方法就是使用它,所以這正是剩下教程中你會(huì)學(xué)到的東西。
注意:自動(dòng)布局不僅對(duì)旋轉(zhuǎn)有作用;它還能輕易的縮放你UI的大小從而適應(yīng)不同尺寸的屏幕。這并不是巧合,當(dāng)iPhone5擁有更高屏幕的同時(shí),這個(gè)技術(shù)也同時(shí)加到了iOS中!自動(dòng)布局能輕易的拉伸你程序的用戶界面,從而充滿iPhone5垂直方向上多出來(lái)的空間。隨著iOS7中的動(dòng)態(tài)類型,自動(dòng)布局變得更加重要了。用戶現(xiàn)在可以改變?nèi)肿煮w大小設(shè)置--有了自動(dòng)布局,這將變得非常簡(jiǎn)單。
擁抱約束(courting constraints) 關(guān)閉你當(dāng)前的項(xiàng)目并用Single View Application模板創(chuàng)建一個(gè)新的iPhone項(xiàng)目。叫做"Constraints"。任何用Xcode5創(chuàng)建出來(lái)的項(xiàng)目都會(huì)自動(dòng)假定你會(huì)使用自動(dòng)布局,所以你并不需要額外做任何事情。 點(diǎn)擊Main.storyboard打開(kāi)Interface Builder。拖一個(gè)新的Button到畫(huà)布上。注意當(dāng)你拖拽的時(shí)候,藍(lán)色虛線將會(huì)出現(xiàn)。這寫(xiě)線用來(lái)做向?qū)А? 在屏幕邊緣以及中心的時(shí)候,都會(huì)有向?qū)Ь€: 如果之前你已經(jīng)使用過(guò)Interface Builder,那么你肯定看到過(guò)這些向?qū)Ь€。這對(duì)我們對(duì)齊控件有很大的幫助。 在Xcode4中激活自動(dòng)布局時(shí),向?qū)Ь€有另外一個(gè)目的。你任然可以用他們來(lái)對(duì)齊,但是他們也會(huì)告訴你新的約束將會(huì)在哪兒。如果你將button沿著向?qū)Ь€反方向拖拽到左上角時(shí),Xcode4中的storyboard看起來(lái)便像這樣: 有兩個(gè)藍(lán)色的東西附屬在button上面。這些T-bar形狀的對(duì)象便是約束了。Xcode 4的Interface Builder中不管你將UI控制器放在哪兒,它總是會(huì)給出有效的約束。理論上這聽(tīng)起來(lái)是個(gè)好主意,但是實(shí)踐起來(lái),在Interface Builder中使用自動(dòng)布局卻非常困難。 幸運(yùn)的是,Xcode5中已經(jīng)有所好轉(zhuǎn)。將button拖拽到畫(huà)布上之后并看不到T-bars形狀的東西: 同時(shí)在Document Outline面板中也沒(méi)用Constraints部分。得到結(jié)論:此時(shí)button上并沒(méi)有設(shè)置任何約束。 那這是如何運(yùn)作的呢?我們之前了解的自動(dòng)布局總是需要足夠多的約束才能決定視圖的大小和位置,但是現(xiàn)在我們這兒跟本沒(méi)有約束。確定這是一個(gè)完整的布局? 這這是Xcode5相對(duì)Xcode4來(lái)說(shuō)最大的一個(gè)提升:再也不強(qiáng)制你總是有一個(gè)有效的布局。
注意:1.運(yùn)行一個(gè)無(wú)效布局的程序是不明智的,因?yàn)樽詣?dòng)布局不能正確的計(jì)算需要將視圖放在哪兒。要么視圖的位置是不可預(yù)知的(約束不夠),要么程序?qū)?huì)崩潰(約束過(guò)多)。 2.Xcode4設(shè)法保證總是有足夠多正確的約束來(lái)創(chuàng)建一個(gè)有效的布局。不幸的是,它經(jīng)常會(huì)將你的約束替換為你并不想要的。這會(huì)令人很沮喪,正是因?yàn)檫@個(gè)原因很多開(kāi)發(fā)者放棄了自動(dòng)布局。 3.Xcode5中,當(dāng)你編輯Storyboard時(shí)它允許你有不完整的布局,但它也會(huì)指出哪些地方你還需要修改。使用Interface Builder創(chuàng)建的自動(dòng)布局驅(qū)動(dòng)用戶界面變得更有趣了,使用Xcode5也消耗更少的時(shí)間。 如果你根本不提供任何約束,Xcode自動(dòng)分配一套默認(rèn)的約束,正是我們所知的自動(dòng)約束。它會(huì)在程序built的編譯時(shí)間中去完成這些事,而不是設(shè)計(jì)時(shí)間。當(dāng)你設(shè)計(jì)你的用戶界面時(shí),Xcode5中的自動(dòng)布局為了不參與你的設(shè)計(jì)方法而努力工作,這這是我們喜歡它的原因。 自動(dòng)約束為你的視圖提供一個(gè)固定尺寸和位置。換句話說(shuō),視圖總是擁有跟你在storyboard中看到的一樣的坐標(biāo)。這是非常方便的,因?yàn)檫@就意味著你可以大量的忽視自動(dòng)布局。你可以為那些擁有充分約束的控件不增加約束,只為那些需要特殊規(guī)則的視圖創(chuàng)建約束。 OK,讓我們玩一玩約束并看看他們能做什么。現(xiàn)在,按鈕是在左上角,并且沒(méi)有約束。確認(rèn)按鈕跟兩個(gè)拐角向?qū)Ь€對(duì)齊。 使用Editor\Pin菜單為按鈕增加兩個(gè)新的約束,看起來(lái)像這樣: 這是Leading Space to Superview和Top Space to Superview選項(xiàng)。 所有的約束都會(huì)在Document Outline面板中列出來(lái): 目前有兩個(gè)約束,一個(gè)是button和main view左邊緣的Horizontal Space約束,一個(gè)是button和main view上邊緣的Vertical Space約束。這個(gè)關(guān)系通過(guò)約束描述起來(lái)便是:"button總是位于其父視圖左上角20點(diǎn)處。" 注意:這些其實(shí)都不是非常有用的約束,因?yàn)樗麄冇邢嗤淖詣?dòng)約束。如果你總是想你的button相對(duì)于父視圖左上角,那么你還不如不提供任何約束,讓Xcode為你做這些。 現(xiàn)在拖動(dòng)button并將它放到屏幕的右上角,再次和藍(lán)色向?qū)Ь€對(duì)齊: 哇哦,這里發(fā)生了什么?在Xcode4中這會(huì)破壞舊的約束并賦值一個(gè)基于藍(lán)色向?qū)Ь€的新約束,但是在Xcode5中button保留了現(xiàn)存的約束。但問(wèn)題是button在Interface Builder中的大小和位置再也不和自動(dòng)布局希望基于約束的大小和位置相符合了。這叫做錯(cuò)位的視圖。(misplaced view) 運(yùn)行程序。Button仍然會(huì)出現(xiàn)在屏幕的左上角: 當(dāng)談到自動(dòng)布局,橙色代表壞的。Interface Builder繪制兩個(gè)橙色方塊:一個(gè)是虛線邊框,一個(gè)是實(shí)線邊框。虛線方塊是根據(jù)自動(dòng)布局顯示視圖的frame。實(shí)線方塊是根據(jù)你在屏幕上放置的視圖的frame。這兩個(gè)應(yīng)該吻合的,但是這里并沒(méi)有。 如何修改取決于你想要達(dá)到什么目的: 1.你想讓button附屬于屏幕左邊緣254點(diǎn)處嗎?在這種情況下你需要將現(xiàn)存的Horizontal Space約束變大234點(diǎn)。這正是橙色badge中"+234"的意思。 2.你想讓button附屬于屏幕的右邊緣?那么你需要移除現(xiàn)有的約束并重新創(chuàng)建一個(gè)新的。 刪除Horizontal Space約束。首先在畫(huà)布或Document Outline中選中,然后按鍵盤上的Delete鍵。 注意這次Vertical Space約束變橙色了。直到現(xiàn)在它都是藍(lán)色的。那一個(gè)約束并沒(méi)有任何錯(cuò)誤;它的意思是剩下的沒(méi)有足夠的約束決定button完整的位置。你任然需要在X軸方向增加一個(gè)約束。
Note:你可能會(huì)奇怪,為什么Xcode不為X軸方向自動(dòng)增加一個(gè)約束。Xcode中的規(guī)則是:Xcode只為那些你沒(méi)有設(shè)置任何約束的對(duì)象創(chuàng)建自動(dòng)約束。一旦你增加一個(gè)約束,你便是告訴Xcode你接管了這個(gè)視圖。Xcode將不再增加任何自動(dòng)約束,并希望你為這個(gè)視圖增加需要的約束。 選中button,并選擇Editor\Pin|Trailing Space to Superview.這迫使在button右邊緣和屏幕右邊緣增加一個(gè)新的約束。關(guān)系表達(dá)如下:"button總是位于距離其父視圖右上角20點(diǎn)處。" 運(yùn)行程序并旋轉(zhuǎn)到landscape。注意button如何與屏幕右邊緣保持相同距離: 當(dāng)你放置一個(gè)對(duì)立于向?qū)Ь€的button(或者任何其他視圖)并新建一個(gè)約束時(shí),你會(huì)得到一個(gè)根據(jù)"HIG"(Apple's iOS Human Interface Guidelines document)定義的標(biāo)準(zhǔn)大小的間隔約束。對(duì)于邊框來(lái)說(shuō),標(biāo)準(zhǔn)大小空間是20點(diǎn)。 現(xiàn)在將button向左拖拽一點(diǎn): 由于視圖錯(cuò)位,你得到了一個(gè)橙色虛線邊框。我們假設(shè)這個(gè)button新位置的確是你想要的。創(chuàng)建完一個(gè)約束后做一些細(xì)微的調(diào)整是很常見(jiàn)的,但這卻會(huì)導(dǎo)致橙色方塊出現(xiàn)。一個(gè)修改方法就是移除約束并創(chuàng)建一個(gè)新的,但還有一個(gè)更簡(jiǎn)單的解決方案。 Editor菜單上有一個(gè)Resolve Auto Layout Issues子菜單。從這個(gè)菜單中,選中Update Constraints。就我這個(gè)情況來(lái)說(shuō),這會(huì)告訴Interface Builder需要將約束變大64點(diǎn),像這樣: 很好,T-bars又變藍(lán)了,布局是有效的。在Document Outline中,你可以看到Horizontal Space約束不再有一個(gè)標(biāo)準(zhǔn)的間隔了: 到目前為止你已經(jīng)嘗試過(guò)了Horizontal Space和Vertical Space約束。還有一個(gè)"center"約束。拖拽一個(gè)新的Button對(duì)象到畫(huà)布底部中心,根據(jù)向?qū)Ь€完好入位: 為了保持button在水平方向上一直居中對(duì)齊于父視圖,你需要增加一個(gè)Center X Alignment約束。從Editor菜單選擇Align\Horizontal Center in Container.這會(huì)增加一個(gè)很長(zhǎng)的橙色線段: 線之所以是橙色是因?yàn)槟悴艃H僅指定了button的X軸,但Y軸并沒(méi)有指定約束。使用Editor\Pin菜單在button和視圖底部間增加一個(gè)Vertical Space約束。看起來(lái)像這樣: 如果你不知道原因,這是Bottom Space to Superview選項(xiàng)。Vertical Space約束使button遠(yuǎn)離視圖底部(再一次使用標(biāo)準(zhǔn)間隔)。 運(yùn)行程序并旋轉(zhuǎn)到橫屏模式。甚至在橫屏模式,button也保持在屏幕底部的中心: 這就是你表達(dá)的意思---這個(gè)button始終應(yīng)該位于底部中心。注意,你根本不需要告訴Interface Builder按鈕的坐標(biāo)是什么,除非你想將它固定在視圖上。 通過(guò)自動(dòng)布局,你再也不需要擔(dān)心視圖位置的精確坐標(biāo)或視圖大小了。相反,自動(dòng)布局會(huì)根據(jù)你設(shè)置的約束得到這兩個(gè)參數(shù)。 你可以在button的Size inspector中看到這個(gè)經(jīng)典轉(zhuǎn)移,現(xiàn)在有了很大的不同: 如果不使用自動(dòng)布局,輸入值到X,Y,Width或Height字段將會(huì)改變選中視圖的位置和大小。使用自動(dòng)布局后,你仍然可以輸入新值到這些字段,但是如果你已經(jīng)為視圖設(shè)置了約束,那這可能造成視圖錯(cuò)位。你將不得不更新約束來(lái)匹配新值。 舉個(gè)例子,把button的寬度改為100,畫(huà)布會(huì)變成這樣: Xcode4用Horizontal Space取代Center X Alignment約束,并且button上會(huì)產(chǎn)生一個(gè)新約束強(qiáng)制它的寬度為100 points。然而,Xcode5說(shuō),"如果你想讓button寬度變?yōu)?00 points,對(duì)我來(lái)說(shuō)無(wú)所謂,但是你要知道約束并不是這么說(shuō)的。" 在這種情況下你希望button是100點(diǎn)寬。對(duì)此有一個(gè)特殊的約束類型:Fixed Width約束。首先按一下Undo,這樣button又居中了,T-bars也變藍(lán)了。選中button并選擇Editor\Pin\Width。這會(huì)在button下面放置一個(gè)新T-bar: 選中那個(gè)T-bar并在Attributes inspector中改變Constant為100.不管button的title多大或多小,這都會(huì)強(qiáng)制button的寬總是100點(diǎn)。為了能更好的看清你可以給button設(shè)置一個(gè)背景色: 你也可以在左邊的Document Outline中看到這個(gè)新的Width約束: 與其他約束不同,在button和它的父視圖之間,Width約束只會(huì)應(yīng)用到button本身。你可以將這個(gè)認(rèn)為是一個(gè)button本身和本身之間的約束。 你可能懷疑為什么button之前沒(méi)有Width約束。自動(dòng)布局是為何知道button有多寬? 事情是這樣的:button自己是知道自己有多寬。它根據(jù)自己的title text加上一些padding就行了。如果你為button設(shè)置一個(gè)背景圖片,它也會(huì)考慮進(jìn)去。 這正是我們熟悉的intrinsic content size。并不是所有的控制器都有這個(gè),但大部分是(UILabel是一個(gè)例子)。如果一個(gè)視圖可以計(jì)算自己理想的大小,那么你就不需要為它特別指定Width或Height約束了,你將會(huì)在稍后看到更多相關(guān)內(nèi)容。 為了恢復(fù)button到最佳大小,首先我們需要移除Width約束。然后選中button,并從Editor菜單中選擇Size to Fit Content。這樣就能夠恢復(fù)button的固有的內(nèi)容尺寸了。
孤掌難鳴 向?qū)Ь€不但出現(xiàn)在一個(gè)視圖和它的父視圖之間,而且也會(huì)出現(xiàn)在相同層級(jí)的視圖之間。拖拽一個(gè)新的button到畫(huà)布上進(jìn)行演示。如果你將這個(gè)button拖近其他對(duì)象,這時(shí)他們的向?qū)Ь€將會(huì)開(kāi)始相互影響。 將新button放到之前一個(gè)button的后面完好入位: 這還有一些向?qū)摼€。Interface Builder識(shí)別出這兩個(gè)button可以通過(guò)不同方式對(duì)齊—頂部,中心以及基線。 Xcode4會(huì)將這些顯著的向?qū)Ь€轉(zhuǎn)變成新的約束。但是在Xcode5中,如果你想讓這兩個(gè)button間有約束,你需要自己創(chuàng)建。之前你已經(jīng)使用過(guò)Editor\Pin菜單來(lái)創(chuàng)建這兩個(gè)視圖間的約束,但是還有一個(gè)更簡(jiǎn)單的方式。 選中新的button并按住Ctrl拖拽到另一個(gè)button上,像這樣: 放開(kāi)鼠標(biāo)按鍵,出現(xiàn)一個(gè)彈出框。選擇第一個(gè)選項(xiàng),Horizontal Spacing。 這將會(huì)創(chuàng)建一個(gè)新的約束: 它是橙色的,這意味著這個(gè)button至少還需要另一個(gè)約束。button的大小是知道的(使用intrinsic content size),并且還有一個(gè)button在X軸上的約束。只剩下Y軸沒(méi)有約束了。 這種缺失約束的情況是很容易確定的,但是更復(fù)雜的設(shè)計(jì)可能就沒(méi)這么明顯了。幸運(yùn)的是,你不再需要敏思苦想,Xcode已經(jīng)記錄并可以確切的告訴你缺少了什么。 在Document Outline中會(huì)有一個(gè)紅色的小箭頭,就在View Controller Scene后面。點(diǎn)擊這個(gè)箭頭便會(huì)看到所有Auto Layout問(wèn)題: 我們將Y軸方向缺失的約束加進(jìn)去。按住Ctrl并向下拖拽新的button: 這次彈出菜單有不同的選項(xiàng)了。這次菜單的選項(xiàng)是基于上下文環(huán)境的—你在哪些視圖間拖拽以及鼠標(biāo)移動(dòng)的方向。選擇Bottom Space to Bottom Layout。 現(xiàn)在新button有一個(gè)位于屏幕底部的Vertical Space,也有一個(gè)跟其他button相關(guān)聯(lián)的Horizontal Space。雖然空間非常小(只有8 points),T-bar可能不大容易看到,但它就在那里。 點(diǎn)擊Document Outline里面的Horizontal Space(8): 當(dāng)你選中一個(gè)約束,它會(huì)高亮自己所屬的控制器。這個(gè)特別的約束位于兩個(gè)button之間。這個(gè)約束表達(dá)了:“不管第一個(gè)button在哪兒或多大,第二個(gè)button總是出現(xiàn)在第一個(gè)button的左邊”。 選中黃色背景的button并輸入較長(zhǎng)的label,比如:“A longer label”。輸入完成后,button會(huì)為新的text改變大小,并且另一個(gè)button會(huì)移開(kāi)。 最終,它依附在第一個(gè)button的左邊緣,這正是我們所期望的: 為了更好的摸索這是如何工作的,多練一些吧。拖拽另一個(gè)button到畫(huà)布上并放到黃色button的上方,他們會(huì)垂直方向?qū)R到位(不要試著讓兩個(gè)button的左邊緣對(duì)齊): 為新button設(shè)置一個(gè)綠色背景色,這樣就可以更容易看出它的范圍。 因?yàn)槟銓蓚€(gè)button對(duì)齊在一起,現(xiàn)在他們之間存在HIG推薦的8 points間隔。按住Ctrl在兩個(gè)button之間拖拽將這變?yōu)橐粋€(gè)約束。從彈出菜單中選中Vertical Spacing。 Note:“HIG”是“iOS Human Interface Guidelines”的簡(jiǎn)稱,包含Apple推薦的良好的用戶界面設(shè)計(jì)。任何iOS開(kāi)發(fā)者都有必要讀一讀這個(gè)規(guī)范。HIG解釋了哪些UI元素適合在什么情況下使用,以及最佳使用方式。你可以在這里找到。(https://developer.apple.com/library/ios/DOCUMENTATION/UserExperience/Conceptual/MobileHIG/Introduction/Introduction.html) 然而你并沒(méi)有被限制在controls間的標(biāo)準(zhǔn)間隔。約束是成熟的對(duì)象,就像視圖一樣,因此你可以改變它們的屬性。 選中兩個(gè)button之間的Vertical Space約束。你可以在畫(huà)布上點(diǎn)擊T-bar,雖然這有點(diǎn)麻煩。目前最簡(jiǎn)單的辦法就是在Document Outline里面選擇約束。一旦你選中約束,再切換到Attributes inspector: 在Constant字段里輸入40改變約束大小。現(xiàn)在兩個(gè)button更進(jìn)一步的分開(kāi)了,但是他們?nèi)稳皇沁B接在一起的: 運(yùn)行程序并翻轉(zhuǎn)到landscape模式查看效果: button必然會(huì)保持他們垂直方向的排列,但是水平方向就不了!原因很明顯:綠色button還沒(méi)有X軸方向的約束。 為綠色button增加一個(gè)到屏幕左邊緣的Horizontal Space并不能解決問(wèn)題。這樣的約束只會(huì)讓綠色按鈕總是保持在同一個(gè)X軸坐標(biāo),即便是在橫屏模式下。這看起來(lái)感覺(jué)不大對(duì),所以你需要表述這樣一個(gè)目的: “黃色button會(huì)一直水平居中,藍(lán)色button左邊緣會(huì)一直跟黃色button左邊緣對(duì)齊。” 你已經(jīng)為第一種情況創(chuàng)建了一個(gè)約束,但是第二個(gè)并沒(méi)有。Interface Builder為對(duì)齊顯示了向?qū)Ь€,這樣你就可以將上面button一直拖拽到跟黃色左邊緣對(duì)齊的位置: 如果你也在垂直方向上拖拽button,這時(shí)button框架和Vertical Space約束之間就不能達(dá)到正確的距離了。你在T-bar上將會(huì)看到橙色的badge: 如果發(fā)生這樣的情況,簡(jiǎn)單的使用方向鍵將button微調(diào)到位,直到badge消失。 最終,按住Ctrl在兩個(gè)button間拖拽,從彈出菜單中選擇Left。這會(huì)創(chuàng)建一個(gè)約束:“兩個(gè)視圖的左邊緣一直對(duì)齊”。換句話說(shuō),這兩個(gè)button一直會(huì)有相同的X軸坐標(biāo)。這時(shí)T-bars變成藍(lán)色了: 運(yùn)行程序并旋轉(zhuǎn)到橫屏模式:
何去何從? 現(xiàn)在你已經(jīng)對(duì)自動(dòng)布局進(jìn)行了第一次嘗試,感覺(jué)怎么樣?這可能需要一些時(shí)間習(xí)慣,但是它能讓你的工作更加簡(jiǎn)單,也會(huì)讓你的app更加靈活。 想要學(xué)習(xí)更多的內(nèi)容?繼續(xù)閱讀第二部分吧,你將會(huì)繼續(xù)在Interface Builder中使用button進(jìn)一步理解Auto Layout提供的多種可能性,以及你可能遇到的問(wèn)題。 最重要的是,你將會(huì)使用Auto Layout在一個(gè)真實(shí)的程序中創(chuàng)建一個(gè)逼真的布局。
CocoaChina是全球最大的蘋(píng)果開(kāi)發(fā)中文社區(qū),官方微信每日定時(shí)推送各種精彩的研發(fā)教程資源和工具,介紹app推廣營(yíng)銷經(jīng)驗(yàn),最新企業(yè)招聘和外包信息,以及Cocos2d引擎、Cocos Studio開(kāi)發(fā)工具包的最新動(dòng)態(tài)及培訓(xùn)信息。關(guān)注微信可以第一時(shí)間了解最新產(chǎn)品和服務(wù)動(dòng)態(tài),微信在手,天下我有!
請(qǐng)搜索微信號(hào)“CocoaChina”關(guān)注我們!
總結(jié)
以上是生活随笔為你收集整理的【转】开始iOS 7中自动布局教程(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。