翻譯:iOS 7中的自動(dòng)布局教程第1部分:入門

本文內(nèi)容:參考外文學(xué)習(xí)并使用Auto Layout,順便翻譯記錄。

原文


iOS 9, Xcode 7, Swift 2 環(huán)境下可以參考:

iOS 7中的自動(dòng)布局教程第1部分:入門

來自Ray的注釋:教程團(tuán)隊(duì)成員 Matthijs Hollemans(iOS Apprentice系列作者)已將此教程移植到iOS 7作為 iOS 7系列 的一部分。我們希望你會(huì)喜歡!

設(shè)想這樣一個(gè)場景,如果你想讓你的應(yīng)用程序能夠在手機(jī)豎屏和橫屏狀態(tài)下都能正常顯示,但是調(diào)試起來卻是一件足夠令人崩潰的事情。另外,想要約束屏幕布局讓APP同時(shí)支持iPhone和iPad,是否是一件足以把你逼到絕望邊緣的事情? 別灰心,這篇文章會(huì)給你帶來好消息!

為屏幕設(shè)計(jì)一個(gè)總是能保證大小相同的用戶界面并不困難,但如果屏幕的frame是可以改變的,UI元素的位置和大小也必須適應(yīng)這些新的尺寸變化。

到目前為止,如果你的設(shè)計(jì)是相當(dāng)復(fù)雜的,你就必須編寫大量的代碼來支持這種自適應(yīng)布局。 你會(huì)很高興聽到這再也不是個(gè)麻煩了——iOS 6給iPhone和iPad帶來了一個(gè)非常棒的新功能:自動(dòng)布局(Auto Layout)。 Xcode 5和iOS 7讓它實(shí)現(xiàn)得更好!如果你嘗試在Xcode 4中實(shí)現(xiàn)自動(dòng)布局并想放棄時(shí),那么你真的應(yīng)該給Xcode 5一個(gè)機(jī)會(huì)了。

Auto Layout不僅可以輕松地在應(yīng)用程序中支持不同的屏幕的尺寸,而且還可以使國際化實(shí)現(xiàn)變得非常方便。你不再需要為希望支持的每種語言創(chuàng)建新的nib文件或storyboard文件,這包括從右到左的語言,如希伯來語(Hebrew)或阿拉伯語(Arabic)。

此自動(dòng)布局教程將向您介紹如何在Interface Builder中開始使用自動(dòng)布局。 在iOS 6 by Tutorials Third Edition教程中,我們將本教程向深層次推進(jìn),然后會(huì)有一個(gè)新的章節(jié),基于這些知識,并展示如何通過代碼實(shí)現(xiàn)Auto Layout的全部功能。

提示:我們正在將基于iOS 6上的所有教程到更新到iOS 7 上——這是一個(gè)預(yù)覽版本! 當(dāng)我們完成所有的更新后,更新將免費(fèi)下載到所有iOS 6的Tutorials PDF客戶手中。

所以吃著點(diǎn)心和你最喜歡的咖啡飲料,準(zhǔn)備好成為一個(gè)自動(dòng)布局(Auto Layout)大師吧!

彈簧和支柱(Autosizing)的問題

毫無疑問你一定對autosizing masks非常熟悉 - 它也常被稱為“彈簧和支柱”模型。 autosizing masks確定了當(dāng)父視圖更改大小時(shí),相應(yīng)子視圖發(fā)生的改變。 它是否有靈活或固定的邊距(margins)(支柱),以及它的寬度和高度(彈簧)發(fā)生的變化?

例如,如果子視圖使用靈活可變的寬度,當(dāng)父視圖變得更寬時(shí),則子視圖將成比例地變寬。 如果使用固定的右邊距,子視圖的右邊緣將始終貼著父視圖(superview)的右邊緣。

Autosizing 系統(tǒng)適用于簡單的情況,但是當(dāng)你的布局變得更復(fù)雜時(shí),它很快就會(huì)失效。 讓我們來看一個(gè)彈簧和支柱完全失效的例子。

打開Xcode 5并創(chuàng)建一個(gè)新的基于 Single View Application 模板的iPhone項(xiàng)目。 設(shè)置應(yīng)用程序名為:StrutsProblem

1

點(diǎn)擊 Main.storyboard 以打開Interface Builder(界面生成器)界面。在做任何操作之前,先禁用該storyboard的Auto Layout功能。你可以在右側(cè)工具欄的六個(gè)標(biāo)簽中的第一個(gè) File Inspector (文件檢視器)中執(zhí)行該操作。

2

取消勾選Use Autolayout。 現(xiàn)在storyboard就會(huì)使用舊的支柱和彈簧(struts-and-springs)模型.

譯者注:我在Xcode 8環(huán)境下取消勾選的對話框界面如下:

取消勾選Use Auto Layout后,會(huì)彈出如下對話框:

Trait Variations:用來聲明APP在不同設(shè)備上的不同特征。使用特征變量(Trait Variations)需要 Autolayout 支持,因此如果取消勾選Use Autolayout,那么特征變量(Trait Variations)也會(huì)不可用。

禁用特征變量(Trait Variations)將文檔限制為存儲(chǔ)單個(gè)設(shè)備的數(shù)據(jù)。用于表示目標(biāo)設(shè)備系列的性狀集合的數(shù)據(jù)將被保留,并且所有其他數(shù)據(jù)將被刪除。此外,segues 將被轉(zhuǎn)換為它們的非適應(yīng)性等效。

這里我們點(diǎn)擊 Disable Trait Variations。

注意:使用Xcode 4.5或更高版本創(chuàng)建的任何新的nib或storyboard文件將默認(rèn)開啟Auto Layout。 因?yàn)锳uto Layout是iOS 6及以上系統(tǒng)的新特性,如果你想使用最新的Xcode來開發(fā)與iOS 5兼容的應(yīng)用程序,你需要通過取消選中“Use Autolayout“復(fù)選框,在任何新創(chuàng)建的nib或storyboard上禁用Auto layout。

拖動(dòng)三個(gè)新視圖UIView到主視圖上,并按照這樣的方式排列:

為了便于清晰理解,給每一個(gè)新視圖設(shè)置它們自己的顏色以便于區(qū)分是哪個(gè)。

每個(gè)視圖距離窗口的邊框20pt; 視圖之間的距離也是20pt。 底部視圖是280pt寬,頂部的兩個(gè)視圖都是130 pt寬。 所有的視圖都是254pt高。

運(yùn)行APP在 iPhone Retina 4-inch 模擬器(沒有的話也可以用iPhone SE代替)上,旋轉(zhuǎn)模擬器至橫屏狀態(tài)。這時(shí)APP看起來是這樣子的,并不是我所期待的樣子:

注意:你可以使用菜單欄中的 Hardware\Rotate Left 和 **Rotate Right ** 選項(xiàng)來旋轉(zhuǎn)模擬器,或者通過按住鍵盤 ? 同時(shí)按向左或者向右的方向鍵來實(shí)現(xiàn)屏幕旋轉(zhuǎn)。

相反,你想要APP在橫屏狀態(tài)下應(yīng)該是這樣的:

顯然,autosizing masks為所有三個(gè)視圖留了一些需要設(shè)置的東西。 將左上角視圖的 autosizing設(shè)置更改為:

該操作會(huì)使視圖貼著頂部和左邊緣(但不是底部和右邊緣),并且當(dāng)父視圖更改其大小時(shí)會(huì)調(diào)整子視圖的寬和高。同樣,將右上角視圖的autosizing設(shè)置為:

底部視圖設(shè)置:

再次運(yùn)行APP并且旋轉(zhuǎn)至橫屏狀態(tài),它應(yīng)該看起來是這樣的:

已經(jīng)很接近我們想要的樣式了,但還不完全匹配。視圖之間的距離不正確?;蛘哂昧硪环N說法:視圖的大小比例并不是100%正確的。問題就在于 autosizing masks 告訴子視圖當(dāng)父視圖調(diào)整大小時(shí),子視圖大小隨之改變,但是它無法告訴子視圖以何種方式調(diào)整大小。

你或許可以這樣設(shè)置 autosizing masks - 例如,調(diào)整可變的寬度和高度設(shè)置(彈簧) - 但是你不會(huì)得到三個(gè)視圖之間的距離正好完全是20pt的結(jié)果。

這是為什么呢

要用彈簧和支柱(springs and struts)的方法解決這個(gè)布局問題,不幸的是,你將不得不寫一點(diǎn)代碼。

在旋轉(zhuǎn)UI界面之前,之中和之后,UIKit會(huì)向您的視圖控制器發(fā)送幾個(gè)消息。 您可以截取這些消息以更改UI的布局。 通常,你需要覆寫 viewWillLayoutSubviews 方法以更改需要重新排列的任何視圖的大小。

在這樣做之前,你首先必須聲明插座屬性來引用需要調(diào)整的視圖。

切換到輔助編輯器模式( Assistant Editor mode)(Xcode工具欄上的編輯器工具集上的中間按鈕),然后鼠標(biāo)右擊拖動(dòng)三個(gè)視圖的每個(gè)視圖到 ViewController.m 中:

分別連接每個(gè)視圖到這三個(gè)屬性:

@property (weak, nonatomic) IBOutlet UIView *topLeftView;    
@property (weak, nonatomic) IBOutlet UIView *topRightView;      
@property (weak, nonatomic) IBOutlet UIView *bottomView;     

添加以下代碼到ViewController.m 中:

- (void)viewWillLayoutSubviews
{   
// 譯者注:原文中if的判斷方法在我最新的Xcode 8中嘗試時(shí)發(fā)現(xiàn)被棄用了。
~~if(UIInterfaceOrientationIsLandscape(self.interfaceOrientation))~~
// 換用下面這個(gè)
if(UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
{    
    // 判斷設(shè)備方向:如果是橫屏模式
    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)到新方向時(shí),就會(huì)回調(diào)這段方法。 它先判斷視圖控制器旋轉(zhuǎn)到的方向,并適當(dāng)調(diào)整視圖大小——在這種情況下,使用基于iPhone的已知屏幕尺寸的硬編碼偏移(將可變變量用一個(gè)固定值來代替的方法叫做hard-code)。 此回調(diào)發(fā)生在動(dòng)畫塊中,因此會(huì)以動(dòng)畫的方式調(diào)整視圖大小。

先別運(yùn)行APP,首先你需要恢復(fù)剛才所作的所有三個(gè)視圖的 autosizing masks 設(shè)置,否則自動(dòng)調(diào)整機(jī)制將與您在viewWillLayoutSubviews中的設(shè)置的視圖位置和大小相沖突:

三個(gè)都還原后就可以了。 運(yùn)行APP,旋轉(zhuǎn)到橫屏狀態(tài)。 現(xiàn)在的視圖排列得很好。 旋轉(zhuǎn)回豎屏狀態(tài),驗(yàn)證一切看起來也很好。

這奏效了。代價(jià)就是,你必須為一個(gè)看起來很簡單的布局寫很多的代碼。 想象一下調(diào)整一個(gè)真正復(fù)雜的布局需要花費(fèi)的工夫,尤其是單個(gè)視圖以動(dòng)態(tài)的方式更改大小,或者子視圖的數(shù)量是不確定的情況下。

現(xiàn)在試著在3.5寸的模擬器上運(yùn)行程序。糟糕。視圖的位置和大小又錯(cuò)了,因?yàn)?code>viewWillLayoutSubviews的硬編碼坐標(biāo)是基于4英寸大小的手機(jī)(320x568取代320x480)。你可以增加另一個(gè)if語句判斷屏幕大小,并使用不同的坐標(biāo)集,但是你可以看到這個(gè)方法很快變得不切實(shí)際。

注意:您可以采取的另一種方法是為豎屏和橫屏設(shè)置單獨(dú)的nib文件。 當(dāng)設(shè)備旋轉(zhuǎn)時(shí),您從另一個(gè)nib加載視圖,并替換出現(xiàn)有的nib。 但這仍然需要非常大的工作量,它也增加了許多麻煩,必須設(shè)置兩個(gè)nib文件,而不是一個(gè)。 當(dāng)你使用storyboards而不是nibs時(shí),這種方法是不切實(shí)際的。

Auto Layout (自動(dòng)布局)拯救猿!

現(xiàn)在,你將看到如何使用自動(dòng)布局實(shí)現(xiàn)相同的效果。 首先,從ViewController.m中刪除viewWillLayoutSubviews方法,因?yàn)樵摲椒ú挥脤懭魏未a。

選擇Main.storyboard,并在File inspector中勾選Use Autolayout為該storyboard文件開啟自動(dòng)布局:

注意:自動(dòng)布局始終作用于整個(gè)nib或storyboard文件。 如果選中該框,那么所有插入nib或storyboard中的視圖都將使用自動(dòng)布局。

運(yùn)行APP并且旋轉(zhuǎn)為橫屏狀態(tài),它現(xiàn)在看起來是這樣的:

讓我們把Auto Layout放到Action中。 按住?鍵的同時(shí)單擊頂部的兩個(gè)視圖(綠色和黃色視圖),以便同時(shí)選中這兩個(gè)視圖。 從Xcode的編輯器菜單中,選擇 Pin \ Widths Equal(相等寬度):

還是譯者提示:這一步操作在 Xcode 5 環(huán)境下應(yīng)該入下圖所示,但我在 Xcode 8 的環(huán)境下操作發(fā)現(xiàn)情況已經(jīng)不一樣了,菜單界面都發(fā)生了變化,Editor 里 沒有 Pin 選項(xiàng)了。

所以選中兩個(gè)View之后不妨可以在畫板右下角設(shè)置,之后的很多操作步驟在新Xcode環(huán)境下找不到的話你也可以在這里試試:

再次選中相同的兩個(gè)視圖,然后選擇 Editor\Pin\Horizontal Spacing(水平距離)。(即使在執(zhí)行第一次Pin操作后兩個(gè)視圖看起來是仍然選中,請注意這只是它們處于特殊的布局關(guān)系的一種顯示模式,因此你必須重新選中這兩個(gè)視圖。)

現(xiàn)在storyboard看起來是這樣的:

橙色的“T條”形狀的東西代表視圖之間的約束。 到目前為止,你添加了兩個(gè)約束:兩個(gè)視圖的 Equal Widths (相同寬度)約束(由帶有等號"="的T條表示)和位于兩個(gè)視圖之間的 Horizontal Space(水平距離)約束。約束(Constraints )代表了視圖之間的關(guān)系,它們是使用Auto Layout設(shè)置布局的主要工具。它可能看起來有點(diǎn)可怕,但它實(shí)際上是很直接的描述,一旦你知道這一切意味著什么時(shí)。

要繼續(xù)構(gòu)建此屏幕的布局,請執(zhí)行以下步驟。 每個(gè)步驟都會(huì)添加更多的橙色T條。

對于左邊的視圖,從 Editor\Pin 菜單選擇:

  • Top Space to Superview ——上邊界到父視圖的距離
  • Leading Space to Superview ——左邊界到父視圖的距離

對于右邊的視圖,選擇:

  • Top Space to Superview ——上邊界到父視圖的距離
  • Trailing Space to Superview ——右邊界到父視圖的距離

對于底部那張大視圖:

  • Leading Space to Superview ——左邊界到父視圖的距離
  • Trailing Space to Superview ——右邊界到父視圖的距離
  • Bottom Space to Superview ——下邊界到父視圖的距離

現(xiàn)在你應(yīng)該有了如下的約束:

請注意,T形條仍然是 橙色 的。這就意味著你的布局是不完整的;也就是說自動(dòng)布局沒有足夠的約束來計(jì)算視圖的位置和大小。解決方案是添加更多的約束,直到它們變成 藍(lán)色

按住?并選中所有三個(gè)視圖。從 Editor 菜單中,選擇 Pin\Heights Equally(相等高度)

現(xiàn)在選中左上角視圖和底部視圖(像先前一樣使用?),并選擇 Editor\Pin\Vertical Spacing(垂直距離)。

Interface Builder 應(yīng)該看起來是這樣的:

現(xiàn)在T條已經(jīng)變?yōu)?strong>藍(lán)色了。自動(dòng)布局現(xiàn)在有足夠的信息來計(jì)算有效的布局了。 它看起來有點(diǎn)凌亂,不過這是因?yàn)?strong>Equal Widths和Equal Heights約束占據(jù)了很大空間的緣故。

運(yùn)行APP并且...哇噢,不需要寫一行代碼便運(yùn)行的很好了。不管你在哪個(gè)模擬器上運(yùn)行它;在3.5英寸和4英寸設(shè)備上,布局效果都運(yùn)行良好。

真酷,但是實(shí)際上你到底做了什么你?Auto Layout 允許你表達(dá):布局中的視圖如何相互關(guān)聯(lián),而不是要求你對視圖的大小和位置進(jìn)行硬編碼設(shè)置。

你已經(jīng)把以下關(guān)系——也就是所謂的約束——放入了布局中:

  • 左上角和右上角的視圖總是保持相同的寬度(也就是pin中第一個(gè)widths equally命令)
  • 左上角和右上角視圖的水平距離是20pt(也就是pin中的horizontal spacing命令)
  • 所有的視圖總是有相同的高度(pin中heights equally命令)
  • 頂部兩個(gè)視圖和底部視圖的垂直距離是20pt(pin中的vertical spacing命令)
  • 視圖和屏幕邊緣的距離是20pt (上邊界、下邊界、左邊界和右邊界到父視圖的距離)

這些就足以表達(dá)出讓 Auto Layout 怎么放置視圖,以及當(dāng)屏幕大小改變時(shí)該如何處理了。

你可以在左側(cè)的 Document Outline 中查看所有的約束(constraints)。 當(dāng)你為storyboard開啟Auto Layout時(shí),就添加了名為Constraints的部分。 (如果沒有看到大綱窗格,請單擊Interface Builder窗口底部的箭頭按鈕。)

如果你選中了Document Outline中的一個(gè)約束(constraints),Interface Builder界面就會(huì)通過在約束周圍畫白色輪廓的方式,高亮顯示約束在視圖上的位置,并且還會(huì)為其添加陰影以使其突出顯示。

約束是真實(shí)的對象(NSLayoutConstraint 類),它們也有屬性。例如,選擇在兩個(gè)頂部視圖之間創(chuàng)建填充的約束(名“為Horizontal Space(20)”,請務(wù)必選擇正確),然后切換到Attributes inspector。 你就可以通過編輯Constant字段來更改邊距的大小。

把值設(shè)置為100,然后再次運(yùn)行APP,現(xiàn)在邊距變得更寬了:

當(dāng)你在應(yīng)用程序中描述視圖時(shí),Auto Layoutsprings and struts 更具表達(dá)力。 在本教程的其余部分中,您將了解所有約束以及如何在Interface Builder中應(yīng)用它們以創(chuàng)建不同類型的布局。

Auto Layout 是如何工作的

正如你在上面的測試中所看到的,Auto Layout中的基本工具是約束(constraint)。 約束描述了兩個(gè)視圖之間的幾何關(guān)系。 例如,您可能有一個(gè)約束:
“l(fā)abel A右邊緣和button B左邊緣有20點(diǎn)的空白空間”

自動(dòng)布局采用所有這些約束,并進(jìn)行一些數(shù)學(xué)計(jì)算,計(jì)算出所有視圖的理想位置和大小。 您不再需要自己設(shè)置視圖的frame——自動(dòng)布局會(huì)幫你實(shí)現(xiàn)它,完全基于你在這些視圖上設(shè)置的約束。

自動(dòng)布局以前,你總是需要為視圖的frames設(shè)置硬編碼,要么在Interface Builder中將他們放置在特定的坐標(biāo)中,或通過傳遞一個(gè)rectangle到initWithFrame:,或者設(shè)置視圖的frame,bounds或者center屬性。

對于你剛剛設(shè)置的APP來說,你尤其需要像這樣設(shè)置frames:

還需要為這些視圖設(shè)置自動(dòng)調(diào)整大小的masks:

這再也不是你需要為屏幕設(shè)計(jì)所考慮的東西了。有了Auto Layout(自動(dòng)布局),你需要做的是這些:

視圖的大小和位置不再重要了; 只有約束才是最重要的。當(dāng)然,當(dāng)你拖動(dòng)一個(gè)新的button或label到畫布上時(shí),它將有一定的大小,并且你會(huì)把它放在一個(gè)特定的位置,但這只是一個(gè)設(shè)計(jì)幫助,用來告訴Interface Builder在哪里放置約束 。

想你所想,如你所愿

使用約束的最大優(yōu)點(diǎn)是,你不再需要調(diào)整坐標(biāo)以使你的視圖顯示在正確的位置。 相反,你可以向自動(dòng)布局描述視圖如何相互關(guān)聯(lián),自動(dòng)布局將為您做所有的辛苦工作。 這就是所謂的根據(jù)目的設(shè)計(jì)(designing by intent)。

當(dāng)你根據(jù)目的設(shè)計(jì)時(shí),你表達(dá)的是你想要實(shí)現(xiàn)什么,而不是是如何實(shí)現(xiàn)。你不應(yīng)該說:“該按鈕的左上角坐標(biāo)是(20,230)”,你應(yīng)該說:

按鈕在其父視圖中垂直居中,并且放置在距離父視圖的左邊緣固定的距離處。

使用此描述,自動(dòng)布局可以自動(dòng)計(jì)算按鈕應(yīng)顯示的位置,不用管父視圖的大小。

其他根據(jù)目的設(shè)計(jì)的示例(自動(dòng)布局可以處理所有這些指令):

  • 這兩個(gè)textField應(yīng)該總是保持相同大?。?/li>
  • 這兩個(gè)button應(yīng)該總是同時(shí)移動(dòng);
  • 這四個(gè)label應(yīng)該總是保持右對齊;

這使得你的用戶界面的設(shè)計(jì)更具描述性。你只需定義約束,系統(tǒng)就會(huì)自動(dòng)計(jì)算其frame。

在第一部分你看到,即使為幾個(gè)視圖在橫豎方向上正確的布局都需要做大量的工作。有了自動(dòng)布局,你可以繞過這些麻煩。如果你正確的設(shè)置了約束,那么在橫豎屏方向上,布局將不需要做任何改變。

使用自動(dòng)布局另一個(gè)重要的好處就是國際化。比如德語中的文本,出了名的比老奶奶的裹腳布還要長,適配起來是一件很麻煩的事。再次,自動(dòng)布局釋放了程序員的雙手,因?yàn)樗芨鶕?jù)label需要顯示的內(nèi)容自動(dòng)改變label的大小。

添加對德語,法語或任何其他語言的支持現(xiàn)在只是一個(gè)設(shè)置約束的問題,翻譯文本...然后就完了!

學(xué)習(xí)自動(dòng)布局最好的方法就是使用它,所以這正是剩下教程中你會(huì)學(xué)到的東西。

注意:自動(dòng)布局不僅對旋轉(zhuǎn)有作用;它還能輕易的縮放你UI的大小從而適應(yīng)不同尺寸的屏幕。這并不是巧合,當(dāng)iPhone5擁有更高屏幕的同時(shí),這個(gè)技術(shù)也同時(shí)加到了iOS中!自動(dòng)布局能輕易的拉伸你程序的用戶界面,從而充滿iPhone5垂直方向上多出來的空間。隨著iOS7中的動(dòng)態(tài)類型的出現(xiàn),自動(dòng)布局變得更加重要了。用戶現(xiàn)在可以改變?nèi)肿煮w大小設(shè)置--有了自動(dòng)布局,這將變得非常簡單。

擁抱約束(courting constraints)

關(guān)閉你當(dāng)前的項(xiàng)目并用 Single View Application 模板創(chuàng)建一個(gè)新的iPhone項(xiàng)目。叫做"Constraints"。任何用Xcode5創(chuàng)建出來的項(xiàng)目都會(huì)自動(dòng)假定你會(huì)使用自動(dòng)布局,所以你并不需要額外做任何事情。

點(diǎn)擊Main.storyboard打開Interface Builder。 將一個(gè)新按鈕拖動(dòng)到畫布上。 請注意,當(dāng)您拖動(dòng)時(shí),會(huì)出現(xiàn)藍(lán)色虛線。 這些線用來做向?qū)В?/p>

將控件拖動(dòng)到在屏幕邊緣以及中心的時(shí)候,都會(huì)有向?qū)Ь€出現(xiàn):

如果之前你已經(jīng)使用過Interface Builder,那么你肯定看到過這些向?qū)Ь€。這些對我們對齊控件有很大的幫助。

在啟用自動(dòng)布局的Xcode 4中,指南有不同的用途。你仍然使用它們來對齊,但他們也告訴你新的約束會(huì)在哪里。如果你將button沿著向?qū)Ь€反方向拖拽到左上角時(shí),Xcode 4中的storyboard會(huì)是這樣的:

有兩個(gè)藍(lán)色的東西附屬在button上面。這些T-bar形狀的對象便是約束了。在Xcode 4的Interface Builder中不管你將UI控制器放在哪兒,它總是會(huì)給出有效的約束。理論上這聽起來是個(gè)好主意,但是實(shí)際上,在Interface Builder中使用自動(dòng)布局卻非常困難。

幸運(yùn)的是,在Xcode 5中使用的情況變好了。當(dāng)你將按鈕放到畫布上后,沒有任何T形條可見了:

注意到Document Outline窗格中也沒有“約束”部分。結(jié)論就是:這個(gè)按鈕沒有設(shè)置任何約束。

但是這又是如何奏效的呢?你剛剛也有了解到,Auto Layout總是需要足夠的約束來確定所有視圖的大小和位置,但在這里你根本沒有設(shè)置任何約束。很明顯這難道不是一個(gè)不完整的布局嗎?

這就是Xcode 5比Xcode 4有所提升的地方:它不再強(qiáng)迫你總是去設(shè)置一個(gè)有效的布局。

注意:

  • 運(yùn)行帶有無效布局的應(yīng)用程序是一個(gè)壞主意,因?yàn)樽詣?dòng)布局無法正確計(jì)算視圖應(yīng)該在哪里。 要么視圖的位置將是不可預(yù)測的(如果沒有足夠的約束)或是應(yīng)用程序?qū)?huì)崩潰(如果有太多的約束)。
  • Xcode 4試圖通過確保總是有足夠的約束來創(chuàng)建有效的布局來防止這種情況的發(fā)生。 不幸的是,它通常通過刪除你自己的約束并用你實(shí)際上不想要的約束來替換它們。 這是非常令人沮喪的,這也是許多開發(fā)人員放棄使用Auto Layout的原因。
    Xcode5中,當(dāng)你編輯Storyboard時(shí)它允許你有不完整的布局,但它也會(huì)指出哪些地方你還需要修改。使用Interface Builder創(chuàng)建的自動(dòng)布局驅(qū)動(dòng)用戶界面變得更有趣了,使用Xcode5也消耗更少的時(shí)間。
  • 如果你根本不提供任何約束,Xcode自動(dòng)分配一套默認(rèn)的約束,正是我們所知的automatic constraints(自動(dòng)約束)。它會(huì)在程序built的編譯時(shí)間中去完成這些事,而不是設(shè)計(jì)時(shí)間。當(dāng)你設(shè)計(jì)你的用戶界面時(shí),Xcode5中的自動(dòng)布局為了不參與你的設(shè)計(jì)方法而努力工作,這這是我們喜歡它的原因。

自動(dòng)約束為你的視圖提供一個(gè)固定尺寸和位置。換句話說,視圖總是擁有跟你在storyboard中看到的一樣的坐標(biāo)。這是非常方便的,因?yàn)檫@就意味著你可以大量的忽視自動(dòng)布局。你可以為那些擁有充分約束的控件不增加約束,只為那些需要特殊規(guī)則的視圖創(chuàng)建約束。

好吧,讓我們來使用一下約束,看看他們能做些什么。現(xiàn)在,按鈕位于左上角并且沒有約束。請確保按鈕是與兩個(gè)角導(dǎo)軌對齊的。

使用Editor\Pin菜單為按鈕增加兩個(gè)新的約束,看起來像這樣:

如果你還沒有猜到,這就是Leading Space to SuperviewTop Space to Superview 選項(xiàng)。

所有的約束也列在Interface Builder窗口左側(cè)的Document Outline窗格中:

目前有兩個(gè)約束,即按鈕和主視圖的左邊緣之間的水平距離,以及按鈕和主視圖的頂部邊緣之間的垂直距離。 描述這些約束表達(dá)的關(guān)系就是:

該按鈕始終位于其父視圖中左上角的20點(diǎn)位置。

注意:這些實(shí)際上并不是非常有用的約束,因?yàn)樗鼈兣c自動(dòng)約束所做的事相同。 如果你總是希望你的按鈕位于它父視圖的左上角,那么你可能不需要提供任何約束,你可以讓Xcode幫你完成。

現(xiàn)在拖動(dòng)button并將它放到屏幕的右上角,再次和藍(lán)色向?qū)Ь€對齊:

哇,這里發(fā)生了什么?在Xcode 4中,這將破壞舊的約束并基于藍(lán)色引導(dǎo)線分配新的約束,但在Xcode 5中,按鈕保留現(xiàn)有的約束。這里的問題是,【Interface Builder中按鈕的大小和位置】與【Auto Layout中基于約束所設(shè)置的大小和位置】不一致。我們稱之為 misplaced view(錯(cuò)位視圖)。

運(yùn)行APP。該按鈕仍將顯示在屏幕的左上角:

對于Auto Layout來說,橙色代表著問題所在。 Interface Builder繪制了兩個(gè)橙色框:一個(gè)帶有虛線的邊框,一個(gè)帶有實(shí)線的邊框。 虛線框展示的是根據(jù)Auto Layout約束顯示的視圖邊框。 實(shí)心橙色框是根據(jù)你對視圖的拖動(dòng)顯示在屏幕中的邊框。 這兩個(gè)邊框應(yīng)該是匹配一致的,但在這里他們并不匹配。

如何解決這個(gè)問題取決于你想實(shí)現(xiàn)什么:

  • 如果你想要將按鈕放在屏幕的左邊,而左邊邊緣距離拖放的視圖234點(diǎn)位置, 在這種情況下,你已經(jīng)使現(xiàn)有視圖的水平空間約束增加了234pt。 這就是橙色線條用“+234”的意思。
  • 如果你要將按鈕放在屏幕的右邊,那么,你需要?jiǎng)h除現(xiàn)有的約束并創(chuàng)建一個(gè)新的約束。

刪除水平空間約束。首先在畫布或 Document Outline 中選擇它,然后按鍵盤上的Delete鍵。

請注意,這步操作會(huì)將垂直空間約束變?yōu)槌壬?,而剛才它是藍(lán)色的。這個(gè)特定的約束并沒有錯(cuò)誤;它只是意味著沒有足夠的約束來確定按鈕的完整位置。你仍然需要為X位置添加約束。

注意:你可能想知道為什么Xcode不為X位置添加一個(gè)自動(dòng)約束。 規(guī)則是:只有當(dāng)你沒有人為設(shè)置任何約束時(shí),Xcode才會(huì)創(chuàng)建自動(dòng)約束。而一旦只要你添加了一個(gè)約束,這就意味著你告訴Xcode,這個(gè)視圖的約束由你管理,不需要Xcode插手來自動(dòng)添加。因此,Xcode將不再進(jìn)行任何自動(dòng)約束,并希望你添加此視圖所需要的任何其他約束。

選中按鈕,選擇 Editor\Pin\Trailing Space to Superview。 這個(gè)步驟會(huì)在按鈕的右邊緣和屏幕的右邊緣之間產(chǎn)生新的約束。 該約束表達(dá)的關(guān)系是:
“這個(gè)按鈕總是位于它的superview的右上角20px?!?br> 運(yùn)行APP并旋轉(zhuǎn)模擬器到橫屏狀態(tài)。 請注意查看按鈕與右邊屏幕邊緣的距離是否始終相同:

當(dāng)你將按鈕(或任何其他視圖)參照引導(dǎo)并設(shè)置約束時(shí),你將獲得一個(gè)由Apple的iOS人機(jī)交互指南 (即HIG)定義的標(biāo)準(zhǔn)尺寸的間距約束。 對于邊框周圍的邊緣距離,標(biāo)準(zhǔn)大小為20px的空間。

現(xiàn)在,將按鈕向左拖動(dòng)一點(diǎn):

同樣你又得到了一個(gè)橙色的虛線框,因?yàn)橐晥D產(chǎn)生了misplaced view(錯(cuò)位視圖)。如果說這個(gè)新的按鈕位置確實(shí)是你想要的。這是常見的約束設(shè)置,只要微調(diào)視圖的幾個(gè)像素,橙色框就會(huì)出現(xiàn)。解決該問題的一種方法是刪除舊約束并創(chuàng)建一個(gè)新的約束,但有一個(gè)更簡單的解決方案。

Editor菜單有一個(gè)Resolve Auto Layout Issues子菜單。 從該菜單中,選擇Update Constraints更新約束。在我的這種情況下,這就告訴了Interface Builder,它的約束需要增大64px,如下所示:

太棒了,T條又變成藍(lán)色并且布局也是有效的。在Document Outline(文檔大綱)中,你可以看到水平空間約束不再有標(biāo)準(zhǔn)空間的那個(gè)約束了:

到目前為止,你已經(jīng)嘗試使用了水平空間和垂直空間約束。 還有一個(gè)“中心”約束。將一個(gè)新的Button對象拖動(dòng)到畫布的底部中心,以便它與指引位置相同:

為了使按鈕始終相對于父視圖居中對齊,在水平軸上,你需要添加 Center X Alignment(中心對齊)約束。 從Editor菜單中選擇Align\Horizontal Center in Container。 這個(gè)步驟會(huì)增加了一條長的橙色線條:

該線是橙色的,因?yàn)槟阒恢付税粹o的X坐標(biāo),而沒有指明其Y坐標(biāo)發(fā)生了什么。 使用Editor \ Pin菜單在視圖的按鈕和底部之間添加垂直空間約束。 它應(yīng)該看起來像這樣:

如果你不知道如何操作,它是Bottom Space to Superview選項(xiàng)。 垂直空間約束使按鈕遠(yuǎn)離視圖的底部(再次使用標(biāo)準(zhǔn)邊距20px)。

運(yùn)行APP并將其旋轉(zhuǎn)到橫屏狀態(tài)。 即使在橫屏模式下,按鈕仍停留在屏幕的底部中心:


這就是你所表達(dá)的意圖:“這個(gè)按鈕應(yīng)該始終在底部中心。”注意,你并沒有告訴Interface Builder該按鈕的坐標(biāo)是什么,你只是希望它被錨定在視圖底部中心。

有了 Auto Layout,你不再需要關(guān)心在畫布上放置視圖的位置的確切坐標(biāo)或它們的大小。相反,Auto Layout 會(huì)根據(jù)你設(shè)置的約束中導(dǎo)出這兩個(gè)東西。

您可以在按鈕的Size inspector(大小檢視器)中看到這種模式轉(zhuǎn)換,現(xiàn)在已經(jīng)非常不同了:

禁用自動(dòng)布局后,輸入X,Y,寬度或高度字段將更改所選視圖的位置和大小。 啟用自動(dòng)布局后,您仍然可以在這些字段中鍵入新值,但是如果您已經(jīng)在視圖上設(shè)置了約束,它現(xiàn)在可能會(huì)放錯(cuò)位置。 您還必須更新約束以使其與新值匹配。

例如,將按鈕的寬度值更改為100.畫布變成這樣:

Xcode 4 會(huì)用水平空間的新約束替換掉中心X對齊約束,強(qiáng)制它具有100點(diǎn)的寬度。然而,Xcode 5簡單地說,“如果你想要的寬度是100點(diǎn),對我來說無所謂,但是你要知道約束并不是這么說的。

在這種情況下,你希望按鈕是100點(diǎn)寬。 對此有一種特殊類型的約束:the Fixed Width constraint(固定寬度約束)。 首先按撤消,使按鈕再次居中,T條全部為藍(lán)色。 選擇按鈕并選擇Editor \ Pin \ Width。 這會(huì)在按鈕下方放置一個(gè)新的T形條:

選擇該T條,并在Attributes inspector(屬性檢視器)中將常數(shù)更改為100.這將強(qiáng)制按鈕總是100點(diǎn)寬,無論它的標(biāo)題多大或小。 要看到這一點(diǎn),你可以給按鈕一個(gè)背景顏色:

您還可以在左側(cè)的Document Outline中看到此新寬度約束:

與按鈕及其父視圖之間的其他約束不同,寬度約束僅適用于按鈕本身。 你可以認(rèn)為這是按鈕和...按鈕之間的約束。

你可能想知道為什么按鈕之前沒有寬度約束。 Auto Layout如何知道按鈕有多寬?

這里有一條就是:按鈕本身是知道它自己必須有多寬的。 它是基于其標(biāo)題文本和一些填充來計(jì)算的。 如果你在按鈕上設(shè)置了一個(gè)背景圖片,它也會(huì)考慮到這一點(diǎn)。

這稱之為intrinsic content size(固有內(nèi)容大?。?/strong>。 不是所有的控件都有這個(gè),但很多(UILabel是另一個(gè)例子)。 如果視圖可以計(jì)算自己的應(yīng)有大小,那么您不需要在為其設(shè)置特定的寬度或高度約束。 以后你會(huì)看到更多的。

要將按鈕恢復(fù)到最佳大小,請先刪除寬度約束。 然后選擇按鈕,從編輯器菜單中選擇Size to Fit Content(大小適應(yīng)內(nèi)容)。這將恢復(fù)按鈕的固有內(nèi)容大小。

孤掌難鳴

引導(dǎo)線不僅僅呈現(xiàn)視圖及其父視圖之間的關(guān)系,而且也呈現(xiàn)視圖層次結(jié)構(gòu)的同一級別的視圖之間。 為了演示這一點(diǎn),將一個(gè)新按鈕拖到畫布上。 如果將此按鈕拖動(dòng)到其他按鈕附近,則它們的引導(dǎo)線也會(huì)開始交互。

將新按鈕放在現(xiàn)有按鈕旁邊,使其卡入到位:

這里有很多虛線的引導(dǎo)線。 Interface Builder認(rèn)為這兩個(gè)按鈕可以以不同的方式排列 - 在它們的頂部,中心和基線。
Xcode 4將把這些貼緊引導(dǎo)下中的一個(gè)轉(zhuǎn)換成新的約束。 但是使用Xcode 5,如果你想在這兩個(gè)按鈕之間有一個(gè)約束,你必須自己做。 您已經(jīng)看到,您可以使用Editor \ Pin菜單在兩個(gè)視圖之間創(chuàng)建約束,但也有一種更簡單的方法。
選擇新的按鈕,然后Ctrl-drag到另一個(gè)按鈕,像這樣:

當(dāng)您松開鼠標(biāo)按鈕時(shí),會(huì)出現(xiàn)一個(gè)彈出窗口。 選擇第一個(gè)選項(xiàng),Horizontal Spacing(水平間距)。

它會(huì)創(chuàng)建一個(gè)像這樣的新約束:

它是橙色的,意味著此按鈕需要至少一個(gè)其他約束。 按鈕的大小是已知的 - 它使用固有內(nèi)容大小確定 - 并且按鈕的X位置已經(jīng)有一個(gè)約束了。 只留下Y位置沒有約束。

這里缺少的約束很容易確定,但對于更復(fù)雜的設(shè)計(jì),它可能不會(huì)總是立即顯而易見的。 幸運(yùn)的是,你不必猜測。 Xcode會(huì)一直保持計(jì)算,可以準(zhǔn)確地告訴你缺少什么。
在文檔大綱中有一個(gè)小的紅色箭頭,在View Controller Scene旁邊。 單擊該箭頭以查看所有自動(dòng)布局問題的列表:

真貼心!讓我們添加那個(gè)缺少Y位置的約束吧。選擇新按鈕向下拖動(dòng):

此時(shí)彈出菜單有不同的選項(xiàng)。此菜單中的項(xiàng)目取決于上下文(您在其間拖動(dòng)的視圖)和移動(dòng)鼠標(biāo)的方向。 選擇Bottom Space to Bottom Layout(底部空間到底部布局)。

新按鈕現(xiàn)在有一個(gè)到屏幕底部的垂直空間,還有一個(gè)水平空間,它與其他按鈕鏈接。 因?yàn)檫@個(gè)空間很?。ㄖ挥?分),T條可能有點(diǎn)難以看到,但它絕對存在。

單擊文檔大綱中的Horizontal Space (8)約束將其選中:

當(dāng)選擇約束時(shí),它會(huì)點(diǎn)亮其所屬的控件。 這個(gè)特定約束位于兩個(gè)按鈕之間。 你在這里做的是說:

“第二個(gè)按鈕總是出現(xiàn)在第一個(gè)按鈕的左邊,無論第一個(gè)按鈕位于何處或有多大。

選擇黃色的按鈕,并在其標(biāo)簽中鍵入一些長的“A longer label”。 完成后,按鈕會(huì)調(diào)整大小,為新文本騰出空間,而另一個(gè)按鈕則會(huì)移動(dòng)。畢竟,它被附加到第一個(gè)按鈕的左邊緣,所以這是你打算發(fā)生的事情:

只是為了獲得【這是如何工作的】更好感覺,再試一次。 將另一個(gè)按鈕拖動(dòng)到畫布中,并將其放在黃色的上方,以便它們垂直卡入到位(但不要嘗試對齊兩個(gè)按鈕的左邊緣):

給新按鈕設(shè)置一個(gè)背景顏色(綠色),這樣你可以更容易地看到它的范圍。

因?yàn)槟惆褍蓚€(gè)按鈕扣在一起,根據(jù)HIG的推薦現(xiàn)在它們之間有一個(gè)標(biāo)準(zhǔn)的8pt空間。 通過在兩個(gè)按鈕之間按住Ctrl鍵并拖動(dòng),將其轉(zhuǎn)換為約束。 從彈出菜單中選擇Vertical Spacing(垂直間距)。

注意:“HIG”是iOS人機(jī)交互指南的縮寫,包含Apple關(guān)于設(shè)計(jì)良好用戶界面的建議。 這是任何iOS開發(fā)人員的必須要閱讀的。 HIG解釋了哪些UI元素適合在哪些情況下使用,以及使用它們的最佳做法。 您可以在此處找到此文檔。

但是,您并不受限于控件之間的標(biāo)準(zhǔn)間距。 約束是完整的對象,就像視圖一樣,因此它們具有可以更改的屬性。

選擇兩個(gè)按鈕之間的垂直空間約束。 你可以通過點(diǎn)擊T條在畫布中做到這一點(diǎn),雖然這往往是有點(diǎn)過于挑剔 到目前為止,最簡單的方法是單擊文檔大綱中的約束。 一旦選擇它,切換到Attributes inspector(屬性檢查器):

在Constant字段中輸入40以更改約束的大小?,F(xiàn)在兩個(gè)按鈕分開了,但它們?nèi)匀贿B接:

運(yùn)行應(yīng)用程序并翻轉(zhuǎn)到橫屏模式以查看效果:

按鈕當(dāng)然仍然保持著垂直排列,但他們不是在同一個(gè)水平位置! 原因應(yīng)該很明顯:綠色按鈕還沒有X位置的約束。

從綠色按鈕向畫布的左邊緣添加水平空間約束將無法解決此問題。 有了這樣的約束,綠色按鈕總是保持相同的X坐標(biāo),即使在橫屏模式下也同樣。 這看起來不是很好,所以你要表達(dá)以下意圖:

“黃色按鈕將始終水平居中,并且綠色按鈕的左邊緣要和黃色按鈕的左邊緣對齊。

您已經(jīng)有第一個(gè)約束了,但還沒有第二個(gè)的約束。 Interface Builder有顯示對齊的指引線,因此您可以拖動(dòng)頂部按鈕,直到其左邊緣與黃色按鈕對齊:

如果您也拖動(dòng)了按鈕的垂直距離,按鈕的邊框和垂直空間約束可能不在正確的距離下。 您將在T形條上看到橙色標(biāo)識:

如果發(fā)生這種情況,只需使用方向鍵將按鈕推入到位,直到標(biāo)識消失。

最后,在兩個(gè)按鈕之間按住Ctrl鍵并拖動(dòng),然后從彈出菜單中選擇Left。 這創(chuàng)建了一個(gè)對齊約束,它的意思是說:“這兩個(gè)視圖的左邊緣總是對齊的”。 換句話說,兩個(gè)按鈕將總是具有完全相同的X位置。 這步解決了布局問題,同時(shí)T條轉(zhuǎn)為藍(lán)色:

運(yùn)行APP,并旋轉(zhuǎn)到橫屏模式以驗(yàn)證其是否有效:


接下來做什么?

現(xiàn)在你已經(jīng)對 Auto Layout 有了第一次嘗試,你喜歡它嗎? 適應(yīng)它可能還要花些功夫,但可以使你的生活很容易,你的應(yīng)用程序也會(huì)更靈活!

想了解更多? 繼續(xù)閱讀本part 2 of this Auto Layout tutorial,您將繼續(xù)使用Interface Builder中的按鈕來更好地了解Auto Layout提供的功能以及您可能遇到的問題。最好就是 - 你也將使用Auto Layout 在你真正的APP中創(chuàng)建一個(gè)真正的布局。

在此期間,如果您有任何問題或意見,請加入下面的論壇討論!

參考文章

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容