天天看點

IOS 6 自動布局 入門 2 (Autolayout)

來自Ray:恭喜各位!你們已經通過宣傳ios feast提前解鎖了第一個有關IOS6的教程。 

目前這份教程隻是我們的新書iOS 6 By Tutorials裡面某個章節的精簡版。這份教程由同樣著作過iOS Apprentice Series的Matthijs Hollemans 完成,開始體驗吧! 

這份教程由IOS 教程小組的組員Matthijs Hollemans釋出,Matthijs既是一位經驗豐富的IOS程式員又是一名資深老到的界面設計者。. 

在這系列教程的第一部分你見識到了舊的“struts-and-springs” 模式不能簡單的解決所有的使用者界面布局問題。新的IOS 6特征是一種解決方案,但因為這個技術是如此的有效,它使用起來還是有點小棘手的。在這系列教程的第二部分也是最後一部分, 你将繼續學習constraint的概念以及如何運用他們! 

大膽嘗試constraint 

也許你已經注意在canvas裡面到有些T型狀對象看上去比其他的要粗一點。這些加粗的,我們稱之為user constraints,你删除它們後的效果和删除細的是不同的。當你删除一個user constraints,Interface Builder經常會自動在删除的地方放置一個不可删除的constraint來代替之。我馬上就會講到為什麼會這樣。

在文檔概要圖中,user constraint有一個藍色按鈕: 

IOS 6 自動布局 入門 2 (Autolayout)

選中 Vertical Space (40) constraint 然後按一下鍵盤上的删除按鈕。 在兩個按鈕之間的T形狀對象消失了,取而代之的是一個新的直接連接配接螢幕底部的Vertical Space constraint : 

IOS 6 自動布局 入門 2 (Autolayout)

新的constraint有一個紫色的按鈕,并且圖中它的線沒有被加粗,這也就代表着它是不可删除的。現在這兩個不再在垂直方向連接配接在一起了。盡管由于Leading Alignment constraint 而依然左邊對齊着。

為什麼會發生這種事情? 為什麼 Interface Builder對按鈕發出了一個新的 Vertical Constraint , 甚至你還沒有告訴它要删除這麼一個constraint?答案是: 

對于每一個view都必須要有足夠的constraints來對其進行位置以及大小的控制。

當用到 Auto Layout時,這是一條最重要的規則。如果對于一個view沒有足夠的 constraints, 它的 Auto Layout 将不能決定它的位置以及大小。 這種布局是被認為無效的。待會你會看到幾個無效布局的例子。 

Interface Builder會盡量幫你避免布局無效。這兩個按鈕的尺寸是可以知道的因為他們根據他們包含的文本,背景圖以及其他的一些東西-固定尺寸内容是可以确定下來他們的尺寸,還記得不?是以這不會是一個問題,上方按鈕的X-位置也可以通過它的左邊界與下方按鈕的左邊界對齊來擷取,而下方按鈕又一直保持着底部居中。現在唯一不确定的就是它的Y-位置。 

之前的話,這兩個按鈕用一個 Vertical Space相連。這個條件足夠能推導出上方按鈕的Y-位置。但如果你删除了Vertical Space,上方按鈕就沒有依據來定位它在view裡的垂直位置了。因為Auto Layout不知道如何決定它的Y位置,是以它不能在螢幕中顯示出來。 

為了避免這種情況發生,Interface Builder需要重新在view中找一個離按鈕底部邊界最近的地方“pin”它。 

IOS 6 自動布局 入門 2 (Autolayout)

有趣的是,當你重新運作程式并且轉動螢幕至景觀方向時,還是之前的效果嘛。這也是正常的,但你的設計确實從根本上就不同了:這兩個按鈕現在都與窗體的底部相連。這也就意味着,當下方按鈕移動時,上方的按鈕不會跟着它一起動了。(注意這個解決方案也不算很好,好不好取決于和你理想的效果是否相同。在這個例子中,你明顯是希望這兩個間有一個vertical connnetion。) 

我們證明一下,選中底下那個按鈕的和螢幕底邊的一個Vertical Space constraint,然後到Attributes inspector ,它的常量現在是“Auto”,目前它是一個标準尺寸,現在把它改為40。

因為這兩個按鈕選擇沒有連結,是以現在隻有下方的按鈕往上面移動了;上方的按鈕還是保持原位: 

IOS 6 自動布局 入門 2 (Autolayout)

注意當改變 constraint常量值時會将它提升為一個 加粗的 “user” constraint。 

針和銷 

現在讓我們把兩個按鈕在再次連接配接在一起。目前為止你通過把按鈕拖進canvas來得到了一些constraints,你可以在稍後做這些。按住Cmd鍵然後同時選中它們,在Editor菜單, 然後選擇PinVertical Spacing。

你也可以通過右下角的小面闆菜單來做這個constraint: 

IOS 6 自動布局 入門 2 (Autolayout)

它會彈出如下菜單:

IOS 6 自動布局 入門 2 (Autolayout)

先不管你選擇了哪種方法, 這個操作在兩個按鈕之間添加了一個新的constraint: 

IOS 6 自動布局 入門 2 (Autolayout)

這個新的constraint是一個有常量為20 points的Vertical Space 。這僅僅是因為當你把兩個按鈕連接配接起來的時候,他們之間的距離是20 points。 

注意原來從上方按鈕到螢幕底部的Vertical Space還是存在的。這個constraint是Vertical Space(104)- 現在已經不需要,是以删了它吧。 

之前當你删除一個藍色constraint的時候,一個紫色會出現并且取代它。現在這種事情不會發生了,因為剩下的constraints已經足夠表達清楚所有view的位置。隻有在現有constraint不夠的情況下,Interface Builder才會添加新的constraint。 

現在你的constraints應該如下所示: 

IOS 6 自動布局 入門 2 (Autolayout)

選中底部的 Vertical Space (通過在canvas上點選) 然後把它的constant 40的值改回為标準值。這步不僅僅應該把下方按鈕往下移,上方的按鈕也該移動。因為現在他們又被連接配接在一起了。 

一個動态運作小測試 

現在你知道的一點基礎知識有:如何使用guides來放置控件,如何使他們相連對齊,如何在空間之間設定空白空間。在這篇教程後,你也會了解到Align and Pin 菜單的其他選項。 

使用Interface Builder 來鼓搗constraints是非常不錯的, 但現在讓我們來看看,在程式運作的時候這個是如何工作的。在?ViewController.m 中加入如下方法: 

- (IBAction)buttonTapped:(UIButton *)sender { if ([[sender titleForState:UIControlStateNormal] isEqualToString:@"X"]) [sender setTitle:@"A very long title for this button" forState:UIControlStateNormal]; else [sender setTitle:@"X" forState:UIControlStateNormal]; }      

這個方法解釋為通過觸發按鈕事件來簡單的切換按鈕标題的長短。從Interface Builder裡面給這兩個按鈕連接配接方法:對每個按鈕按住Ctrl拖至File’s Owner 然後在組裡面選擇buttonTapped:

運作程式看看這會怎麼樣。并且同時在景觀方向和肖像方向設定測試。 

IOS 6 自動布局 入門 2 (Autolayout)

不論你觸碰的是哪個按鈕,現在的頁面布局總是能夠符合你提出的contraints: 

  • 在水準方向,下方的按鈕總是在視窗中水準居中。 
  • 下方的按鈕總是和視窗的底部保持20 points距離。 
  • 上方的按鈕總是和下方的保持左邊界對齊。 

這是你設定的整個使用者界面的規範。 

你可以為了樂趣,同時在Interface Builder選中兩個按鈕,然後從Align菜單選擇Right Edges。然後運作程式注意觀察這其中的差別。 

重複地,但現在請選擇AlignHorizontal Centers。這會使上方的按鈕中心和下方的按鈕的中心對齊。現在運作程式看看這些按鈕是如何工作的。 

修複寬度 

Pin 菜單有一個 Widths Equally選項。 如果你的兩個view設定了這個constraint,那麼Auto Layout 會一直保持兩個view的寬度相等,這個寬度值取決于較寬的那個view。讓我們來對這個做一個實驗。 

選中這兩個按鈕然後在菜單裡選擇?PinWidths Equally。?這步操作為兩個按鈕添加了一個新的constraint: 

IOS 6 自動布局 入門 2 (Autolayout)

提示: 如果兩個按鈕的任意一個與superview有一個你不想要的constraint,那麼請再次同時選中兩個按鈕然後執行 AlignHorizontal Centers選項。 

在這系列教程的第一部分,你其實是已經見識過了這類constraint。這個看上去和普通的T型狀對象類似,但其實在這T型狀對象的中間有一個圈,圈裡是有一個等于号的。 

看,在文檔概要圖裡又多了一個 ?Equal Widths constraint: 

IOS 6 自動布局 入門 2 (Autolayout)

現在改變其中一個按鈕的标簽内容也會同時改變到另外個按鈕的尺寸了。 

把下方按鈕的标簽内容改至 “X”,讓它足夠小。你可以注意到上方按鈕的尺寸不在相容它的内容了: 

IOS 6 自動布局 入門 2 (Autolayout)

那麼Interface Builder是如何知道要選用哪個按鈕的尺寸的呢? 如果你足夠細心的話,你會發現有一個, Width constraint 被加到了上方按鈕: 

IOS 6 自動布局 入門 2 (Autolayout)
IOS 6 自動布局 入門 2 (Autolayout)

Interface Builder 強制上方按鈕變小,為了滿足Equal Widths constraint這個限制條件。 

很明顯這不是你想要的結果,是以請選擇上方按鈕然後在Editor菜單裡為它選擇Size to Fit Content(或者按快捷鍵 Cmd =)。現在,按鈕裡面的文本又能全部看到了 –  或者更科學的說,這個按鈕能夠根據包含的文本而調整大小了 – 另外它的Width constraint也消失了。 

運作程式然後點選按鈕。現在兩個按鈕一直保持相同寬度了,不論哪個按鈕的長度比較寬: 

IOS 6 自動布局 入門 2 (Autolayout)

當然當兩個按鈕都變得非常短時,他們還是會一起縮小到相等寬度。除非有個constraint來做限制,不然的話按鈕控件是會根據他自己包含的内容來不多不少的調整自己的尺寸到一個恰當的大小。這個叫什麼功能呢?對的,這就是固有内容尺寸。 

固有内容尺寸

在 Auto Layout功能出現之前, 你通常會設定你的各種控件該有多大,或者在通過定制他們的frame、bounds屬性來改變大小,或者直接在Interface Builder來改變他們的大小。 但目前的情況是大部分的控件完全有能力基于它們的内容來計算出自生所要占的空間大小。 

一個label能夠通過設定在它上面的文本長度以及文本字型來計算出自己的寬和高。類似地,button,可以通過在它帶有背景的文本以及一些圓角的填充來計算出适合自己的寬和高。 

這也适用于很多分段控件,如一些progress bars,還有許多的其他控件,盡管有一些是有一個預定義的高,但是它寬還是可以設定的。 

這就是所謂的 固有尺寸内容, 在Auto Layout這是一個重要的概念。在按鈕的操作中你已經見識到了吧。. Auto Layout 會先問你的空間他們有多大,然後在基于空間給出的資訊将他們展示到螢幕上去。 

你也可以不使用它,但你要明确設定這個空間的Width 或者 Height constraint。如果你這麼做了,那麼 Interface Builder 為自動生成一個你設定的constraint。如果想要再次恢複固有内容尺寸的話,你隻需重新使用Size to Fit Content 操作, 另外之前你設定的 Width or Height constraints會自動消失. 

通常來說,你使用固有内容尺寸功能就夠了,但有些情況下這功能還是不盡如人意的。想象一下,當你需要在UIImageView上設定一個image的時候,如果那個image要比螢幕大的多,你通常會給image設定一個合适的寬度以及高度來适應UIImageView的内容尺寸,除非你想讓imageview來自動幫你重新設定image的dimensions。 

如果對一個按鈕設定一個固定的 Width constraint,情況會怎麼樣? 雖然按鈕能夠計算自己的尺寸,但是你能通過給他設定一個固定的尺寸來使它的計算無效。選中上方的按鈕然後在菜單選擇PinWidth。 看,按鈕上方有了一個固定的T型狀對象了: 

IOS 6 自動布局 入門 2 (Autolayout)

因為這類的constraint隻應用于按鈕本身,而不是它的superview,它被列在文檔概要圖中的按鈕對象下方。就像你剛才所做的,現在這個按鈕的固定尺寸被設為了73 points。 

運作程式然後點選按鈕,看看發生了什麼?按鈕的文本内容改變了,它不再全部顯示内容了因為缺少足夠多的空間: 

IOS 6 自動布局 入門 2 (Autolayout)

因為上方按鈕有個固定的尺寸又因為兩個按鈕被要求是同一尺寸,是以他們不會再縮小和放大了。 

提示: 你通常的設計理念是不會對一個按鈕設定Width constraint – 最好的情況是讓按鈕使用它自己的固有内容尺寸 – 但當你遇到過一個你希望控件自動改變尺寸而它沒有改變的布局問題時,那麼最好請多次确認一下Interface Builder裡面有沒有一個固定的 Width constraint。 

還是多玩一會這個東西吧以便于你真正掌握 對view對象的pinning 以及aligning 。因為不是所有的現象都很明顯,是以你最好對它有一種感覺。但是請你記住,對于必須要有足夠多的constraints,  Auto Layout 才能對所有的view判斷出位置以及尺寸。 

IOS 6 自動布局 入門 2 (Autolayout)

圖庫執行個體 

現在你應該對constraint是什麼以及知道如何在不同view之間建立關系來構造你的布局。 接下來,你将會看到如何使用 Auto Layout 以及 constraints 來創造一個符合現實世界場景的布局。 

假設你要制作一個關于你最喜歡的程式員的圖庫應用,在景觀和肖像方向,它看上去應該如下圖所示: 

IOS 6 自動布局 入門 2 (Autolayout)

這個螢幕現在被分成了4塊大小相同的部分。每個部分有個imageview以及一個label。你怎麼樣來做到這個呢? 

讓我們重新開始這個程式。你可以使用你現存的“constraints”項目通過把裡面的按鈕全部删光。 

或者,你可以重新建立一個新項目,用 Single View Application 模闆然後你随便給他取一個名字你喜歡的名字。比如說,“畫廊”。這裡面隻需要使用nib檔案,是以請禁用掉storyboards 選項。 

從對象庫打開ViewController.xib檔案, 把一個普通的view放到canvas上。把它的寬設為160 points,高設為230 points, 然後把背景改為你喜歡的某種顔色 (我把它改為綠色):

IOS 6 自動布局 入門 2 (Autolayout)

這個view在它的空間内有4個constraint。不像一個button或者label,一個普通的UIView 沒有固有内容尺寸功能。是以它必須要有足夠的constraints來判定它的位置以及大小,是以現在這個view需要constraints來決定它需要的尺寸大小。 

你可能想知道,這些尺寸的constraints在哪裡?在這種情況下,這些view的尺寸通過他們superview的尺寸來得到。在這個布局中,有兩個Horizontal Spaces 以及兩個Vertical Spaces,并且這些都有固定尺寸。你可以在文檔概要圖中看到這些: 

IOS 6 自動布局 入門 2 (Autolayout)

綠色view的寬度可以通過這個公式 “superview的寬度 減去(109 + 51)” 來計算得到,類似的它的高度可以通過 “superview的高度 減去(153 + 77)”。 因為這些空白constraints被固定了,所有view本身沒有機會來改變大小。但當你轉動應用時,superview的尺寸從320×460變為480×300。把這新的寬度以及高度放到公式中,你會得到一個新的綠色view的尺寸。 

你可以通過運作程式并且轉動至景觀模式看到這個現象,但你也可以直接在 Interface Builder裡直接模拟這種情況。 

選擇nib檔案裡最頂層的view 然後到 Attributes inspector裡去看,在 Simulated Metrics 部分裡, 把方向改為景觀模式: 

IOS 6 自動布局 入門 2 (Autolayout)

這裡可以看到 nib 檔案在景觀方向的直接布局現實。這個綠色view為了要滿足 Horizontal and Vertical Space constraints 而重新改變了它的尺寸。 

再切回到肖像方向。 

提示:現在有兩個理由解釋在nib檔案上你為什麼要用一個普通的UIView : a) 你将要用它來做其他view的容器,使用它可以幫助你組織你nib檔案的内容。; b) 這對于一個定制的view或者control來說是一個占位标志,你可以把它類屬性設定為你自己寫的 UIView或者 UIControl的子類。 

有時當裝置轉動時你不是總希望你的UIView 重新改變大小, 是以現在我們通過 constraints 來定制view的固定寬度/或者高度。我們來動手做一下。 選中綠色view然後在 Pin 菜單, 選擇Width。同樣地再次選中綠色view然後在菜單裡選擇 PinHeight。

你現在可以對view添加兩個新的constraint,一個160 point的Width constraint 和一個230 point Height constraint: 

IOS 6 自動布局 入門 2 (Autolayout)

因為寬度和高度隻适用于這個view,在文檔概要圖中,他們處在view自身的目錄下。通常來說,cnostraints隻表現為兩個view之間的關系 – 比如說,在綠色view和它的灰色superview之間有 Horizontal 和 Vertical Space constraints 這個關系 – 但你也可以認為 Width 和Height constraints 是view和它自身的關系。 

現在運作程式。恩!在肖像方向看上去不錯。 現在把view翻轉至景觀方向。擦! 它的樣子不僅不是你想要的 – 它自身的尺寸又改變了 – 而且Xcode也報了一個令人讨厭的錯誤資訊: 

Gallery[68932:11303] Unable to simultaneously satisfy constraints.  Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "", "", "", "", "" ) Will attempt to recover by breaking constraint    Break on objc_exception_throw to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.      

是否還記得我說過對于view來說必須要有足夠多的constraint,那麼Auto Layout才能計算出所有view的位置以及尺寸?那麼,現在這個例子的情況是它有太多的constraints了。無論何時當你得到錯誤 “Unable to simultaneously satisfy constraints”時, 這在暗示你的constraints在某些地方起沖突了。 

讓我們再來看看那些contraints: 

IOS 6 自動布局 入門 2 (Autolayout)

對于這個綠色view,目前有6個constraint。四個之前你見過,另外兩個新的 Width 和Height 是你剛加上去的。那麼沖突起在哪裡呢? 

那麼, 在肖像模式中數學的計算是沒有問題的。superveiw的尺寸是320 points。如果你把綠色view的寬度再加上Horizontal Space的長度,那麼你應該得到320這個值。我定位綠色view的方式是:51 + 160 + 109 = 320。類似地,垂直vertical constraints 應該加到 460。 

但當你轉到裝置至景觀模式時,主視窗 (也就是它的superview)是 480 points 寬。這意味着 51 + 160 + 109 + ? = 480。 在這等号的左邊還需要一個160 points但是Auto Layout卻不知道去哪裡得到它。類似地,垂直坐标也是這個情況。 

現在我們遇到的沖突為以下兩種情況中的一種,要麼view的寬度是固定的但是它對應的頁邊必須是可以改變大小,要麼它對應的頁邊是固定的但是它的寬度可以改變大小。 在上面的例子中,你想要這個view在兩個方向保持相同的寬度,是以後面的Horizontal Space 必須要删除掉。 

把右邊的 Horizontal Space删除以及把底部的Vertical Space删除。現在 nib 檔案應該看上去這樣了: 

IOS 6 自動布局 入門 2 (Autolayout)

現在這個view已經有恰當數量的constraint來決定它的尺寸以及位置。不多也不少。再次運作程式,可以看到xcode報錯資訊已經沒有了,這個view也在螢幕轉動後保持了相同尺寸。 

提示: 盡管 Interface Builder 已經很努力的幫你避免掉無效的布局了,但是它不是萬能的。 可是至少Auto Layout會為你報出一個詳細的錯誤資訊當你有些設定是錯誤的時候。 在 iOS 6 by Tutorials這本書裡的”Intermediate Auto Layout”你可以學到更多關于如何分析錯誤資訊以及如何診斷布局問題的介紹。 

把肖像畫出來 

在綠色view中拖進一個label。 注意現在的guides是在綠色view中出現了,因為它是label的superview。 

IOS 6 自動布局 入門 2 (Autolayout)

根據guides把label放到綠色view的左上角。這會給label在綠色view中添加兩個 Space constraints 來定位自己: 

IOS 6 自動布局 入門 2 (Autolayout)

注意這兩個新的 Horizontal and Vertical Space constraints 是被列在綠色view的contraints目錄下面而不是main view下。 

現在稍微把綠色view移動一點。你可以看到隻有在綠色view和它的superview之間constraints改變了。而不是label的那些。 這個label會根據綠色view一直待在同一個相同的地方。 

選中label然後把它移動到綠色view的底部邊緣,并使它中心對稱。然後在nib裡拖進去一個新的imageview,使布局看上去如下圖所示: 

IOS 6 自動布局 入門 2 (Autolayout)

把這imageview固定在頂部,以及它superview的左右兩個邊界。但它的底部是通過一個标準spacing與底部标簽相連。 

下載下傳 這份教程的素材 然後解壓檔案。在裡面你會找到一個 Images 檔案夾 – 把它加入到你的項目中去。設定 Ray.png 作為你imageview的image, 然後把 image view的模式改為Aspect Fit并且設定它的背景顔色為白色。接着把label的text寫為“ray”。 

你的布局現在看上去應該是這樣的了:

IOS 6 自動布局 入門 2 (Autolayout)

請注意現在Interface Builder 已經在label上設定一個 Height constraint了。這發生在你為你的image view設定image的時候。 

IOS 6 自動布局 入門 2 (Autolayout)

Interface Builder已經嘗試在避免某種含糊的布局的情況發生。如果image view或者label都沒有一個固定高度的話,那麼Auto Layout是不知道如何重新設定他們的高度的當綠色view變化時。(對于現在而言Interface Builder似乎會忽略設定在綠色view上面的固定Height constraint)。 

讓我們來假設在某種情況下你app裡的綠色view變高了100 points。那麼現在這多出來的100 points在imageview和label當中是如何配置設定的呢?是不是imageview也變高了100 points而label保持原樣呢?或者說是label變高了而imageview保持原樣?或者說他們是對半分的,25/75分,46開?,或者其他某種分法? 

Auto Layout是不會做這些假設的,所有隻有Interface Builder來通過給定label一個固定尺寸“幫助”我們解決這問題。當然它也可以給imageview一個固定尺寸,但是給label是更有意義的。 

對于此刻來說, 讓我們姑且先使用label上面的Height constraint。 

提示: 對小布局設計來說一個比較恰當的解決方法是改變label的“Content Compression Resistance Priority”。這點你以後會學到。如果你等不及了想使用的話,那麼請直接到label的Size inspector for the label然後設定vertical Content Compression Resistance Priority到751。可以到看到label上的 Height constraint會消失掉的。 

加入其他頭像 

把綠色view移動到main view的左上角,是否還記得綠色view的Horizontal Space 以及 Vertical Space constraints 判定了它在superview中的位置。依然還是那些constraints,但是他們現在的值被設為了0 - 藍色線條的就是他們(有白色邊界的) 在window的左上角: 

IOS 6 自動布局 入門 2 (Autolayout)

雖然這個view是完全在角落裡的,但它還是需要constraints來把它定位在那裡。就把他們想象成邊緣值為0吧。 

選中綠色view然後按 Cmd-D 複制。把複制品移到右上角去: 

IOS 6 自動布局 入門 2 (Autolayout)

再分别複制他們把他們移動左下角以及右下角。 

把螢幕設計成如下所示: 

IOS 6 自動布局 入門 2 (Autolayout)

這幾位是比較帥的程式員 :-) 

運作程式,可以看到肖像方向,界面看上去還不錯,但是在景觀方向就不盡如人意了: 

IOS 6 自動布局 入門 2 (Autolayout)

這應該很明顯可以看出錯在哪裡了: 你已經對4個view容器設定了固定的寬和高,是以他們會一直保持這那些尺寸,無論它的superview的尺寸如何變化。 

選中4個view裡面的 Width (160) and Height (230) constraints 然後删除他們。現在運作程式試試,你會得到下圖所示,還是不盡如人意: 

IOS 6 自動布局 入門 2 (Autolayout)

這個問題看上去有點像我們之前在介紹裡面解決過的問題,是以讓我們回想一下當時是如何解決的,你應該記得我們是給view設定相同的寬和高來解決的。 

選中所有4個view然後做 PinWidths Equally操作。再次重新選中然後再做PinHeights Equally操作。 

再次運作程式并且把之轉到景觀方向。嗯….它還是和之前的一樣嘛。這是為什麼呢? 

好吧,如果你仔細觀察上面的截圖,你會發現其實每個view确實都有相同的高度,并且他們的寬度似乎也相同(隻不過綠色的和棕色被黃色和藍色部分遮蓋住了),是以我們的contraints是對的,是的被滿足的。現在的問題僅僅是寬度和高度不是你想要的。如果這是這樣,那麼肯定還有其他constraints在其中起作用了。 

100%肯定,如果你仔細看這些view的constraints,你會看到他們同樣的有Horizontal 以及 Vertical Space constraints來強迫他們定位自己的位置。 (請看main view的constraints,而不是4個子view的): 

IOS 6 自動布局 入門 2 (Autolayout)

更加悲劇的是,你都不能删除這些 constraint,main view的T型狀對象不是藍色粗體,是以可以推斷出 Interface Builder 把他們放在那裡是為了避免某種布局問題的。 

它為什麼要這麼做呢? 目前隻能這麼解釋,所有的4個view都必須擁有相同的尺寸大小是不足以決定他們确切的的尺寸應該是多少的,因為Auto Layout是不知道他們幾個是如何連接配接在一起的。在我們設計上,他們是邊和邊的連接配接在一起,但是他們之前卻沒有這種constraints。是以Auto Layout不會知道它需要把“Ray” and “Matthijs” 塊寬度上需要分開。 

如果Auto Layout不能通過自身才推斷出這層意思的話,那你就隻能自己來告訴他了。 

IOS 6 自動布局 入門 2 (Autolayout)

選中 Ray 和 Matthijs 塊然後選擇 PinHorizontal Spacing操作。因為這些塊是邊與邊相連的,是以在他們之間需要添加一個尺寸為0的Horizontal Space constraint,有了這個, Auto Layout 就知道他們是如何關系的了。 

重要提示: Interface Builder不會自動幫你删除黃色view和superview之間的主導Horizontal Space限制(就是上一張截圖所示的),但它會将它更新為一個user constraint(比較粗的T狀對象)。 你現在可以把它删了。如果你不删的話,你會得到一個“Unable to simultaneously satisfy constraints”的錯誤當你把應用轉至景觀方向時。 

運作程式,看看現在是什麼效果了: 

IOS 6 自動布局 入門 2 (Autolayout)

這個看上稍微好一點了。現在四個view是相同寬度,但高度還是不對的。解決方案和之前的類似:在Ray和Dennis Ritchie之間放一個 Vertical Space然後把Dennis的view和window頂部之間的Vertical Space删除。 

再次運作程式,現在看上去應該是這樣了: 

IOS 6 自動布局 入門 2 (Autolayout)

請注意“Dennis Ritchie” label并不在它imageview的下方正中心。這件事最開始發生在當我想要在label裡輸入文字的時候。這個label初始化時是放在view的中間的,但Interface Builder還是覺得把這個中心constraint替代為一個Horizontal Space效果會更好。如果你也有這個問題,那麼請選中這個label然後進行AlignHorizontal Center in Container操作來修複它。 

請再次注意下這些imageview:他們是延伸出來的,因為你沒有給他們設定一個固定尺寸。你可能還不知道這一點,但設定他們确實是你的義務。:) 在景觀方向下,這些view是不會自動修複的。但是,如果你想要一個imageview保持它原來的比例的話,那你就不是那麼走運了。如果你不使用Interface Builder來做一點修改的話,你是不可能得到下圖的效果的: 

IOS 6 自動布局 入門 2 (Autolayout)

不幸的是, Interface Builder目前不提供一些能保持view原始比例的constraints。要做那個效果,你需要通過代碼自己建立以及設定constraints。在iOS 6 by Tutorials裡面有一章”Intermediate Auto Layout”是介紹具體怎麼做的。 

小貼士:你之前可能已經知道了你可以通過在Simulated Metrics來設定方向以便于你預覽使用者界面。你也可以直接Interface Builder裡面測試各種view的縮放行為。 

選中main view,在Simulated Metrics下,把尺寸設定為Freedom。現在你能nib檔案添加縮放處理,你可以把它設定成你想要的任何型狀。順便也請放心,Auto Layout會馬上重新為你計算出新的布局的: 

IOS 6 自動布局 入門 2 (Autolayout)

然後,你也要對此警惕。因為有時候當你重新設定尺寸時 Interface Builder 會給它自己添加新的constraints。就像現在這兒的右下角有一個新的Horizontal Space一樣。當然這也可能會删除現有的constraints,當你把nib檔案放大出它原來的bounds的時候。 

接下來去哪? 

如果你從頭看到這裡了,那麼恭喜!- 你現在已經知道了關于Auto Layout的所有事情,并且已經對基礎知識做了實踐!但是在這方面還是有許多需要你去學習… 

現在這份教程也就是你剛讀的隻是 iOS 6 by Tutorials 這本書裡 Beginning Auto Layout chapter章節的前半部分。後半部分會教到如何使用 Auto Layout來建立更多 “現實世界”的螢幕布局,以及有關同時使用Auto Layout 和Interface Builder 的所有技巧。 

和其他視覺設計工具一樣, Interface Builder 有它自己的限制但是有時候如果它和 NSLayoutConstraint對象一起使用的話是會效果更好。 iOS 6教程書對于這個主題投入了一整個的章節- Intermediate Auto Layout.。是以如果你想要對此刨根問底的話, 那就買書看吧!

繼續閱讀