IOS 6 自動佈局 入門-1(IOS中autolayout和之前版本autoresize的差異)

http://www.raywenderlich.com/zh-hans/22873/ios-6-%E8%87%AA%E5%8A%A8%E5%B8%83%E5%B1%80-%E5%85%A5%E9%97%A8%EF%BC%8D1



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

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

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

你是否曾經因爲嘗試想讓你的應用同時在景觀方向(橫版)以及肖像方向(豎版)看上去不錯而感到受挫?是否爲了讓應用同時支持iPhone以及iPad的模型尺寸而抓狂?現在我們可以不用爲此而擔心了,我有個好消息帶給大家!

通常來說,如果屏幕是固定尺寸,那麼設計它的用戶界面不會很難,但如果屏幕的frame需要能夠變化,那麼其中各個UI元素的位置以及尺寸也必須爲了適應新的尺寸做相應的變化。

目前爲止,即使你的界面設計是在合理的複雜度內,你也必須要爲之寫許多代碼來適應變化的佈局。現在我相信你會很高興聽到這種情況將不會發生了-對於iPhone與iPad IOS6 帶來了一個非常了不起的特徵:自動佈局。

自動佈局不僅能給你的應用帶來各種屏幕尺寸設計的支持,做爲額外的驚喜,它還能使設計中的各種小事比如多語言環境支持。你從此不必再爲你想要支持的各種語言重新設計nibs和storyboards文件,當然這也包括一些從右至左書寫的語言比如說希伯來文和阿拉伯語。

這篇教程將向你展示的是如何開始使用Iterface Builder來做自動佈局。在iOS 6 by Tutorials裏,我們把這篇教程內容寫得更深,並且基於這個知識會有一個全新的章節,在這裏面你會看到如果通過代碼來釋放自動佈局的全部功能。

好吧,現在開始拿着你喜歡的零食以及飲料,準備開始做一名自動佈局的大師吧!

springs and struts 的問題

毫無疑問你可能對autosizing masks比較熟悉–這個也就是 “springs and struts” 模式。autosizing mask決定了一個view會發生什麼當它的superview 改變大小的時候。它是否有靈活並且自動修復頁邊處理能力(the struts),它的寬和高同時也會發生什麼變化呢(the springs)?

舉個例子,當一個view的superview的寬度變寬時,它的寬度也會靈活地跟着變寬,並且它的右邊界也會自動修復般的一直緊挨着superview的右邊界。

autosizing 系統處理這種簡單的情況還是不錯的,但是當情況稍微複雜一點的時候,它就會很快搞砸你的佈局。現在讓我們看一個springs and struts模式所不能處理的一個簡單例子吧。

打開Xcode創建一個基於Single View Application template新項目,把之命名爲”StrutsProblem”,選擇iPhone程序並且禁用Storyboards:

Project options

在 Interface Builder 裏點擊打開ViewController.xib。在你做任何其他事情之前,請先在nib裏把Auto Layout禁用掉。你可以在File inspector裏找到這個選項:

Disable autolayout

取消選擇“Use Autolayout”複選框. 那麼現在你的nib使用的是舊版本的 struts-and-springs 模式。

提示: 任何你通過Xcode4.5或者更高版本創建的新nib或者storyboard文件會默認使用Auto Layout。因爲Auto Layout這個特性只有在IOS 6中有,所以如果你想要使用 Xcode4.5來做一些兼容IOS5的應用,你必須要在新的nib或者storyboard文件中通過取消選擇“Use Autolayout”複選框來禁用Auto Layout。

拖拉三個新的view到main view中,如圖所示:

Portrait design

爲了使看起來更清晰,我們把每個view都填注顏色。

現在每個View都離窗體邊界 20 points遠;各個填充顏色的view之間的距離也是20 points。底部的view是280 points寬,並且頂部兩個view都設置成130 points寬。所有的view都設置成200 points 高。

運行程序並且把模擬器或者你的設備旋轉至景觀方向。你的設備會如下圖所以,和我們理想的差距甚遠:

Landscape looks bad

提示:你能夠通過使用 HardwareRotate Left and Rotate Right的菜單選項來旋轉模擬器, 或者通過按住Cmd然後使用向左或者向右方向鍵來旋轉。

而我想要的是讓程序運行後是這個樣子的在景觀方向下:

Landscape good

很明顯, autosizing masks 對於要達到這三個view的理想變化還需要做點其他的。 從左上角的View來開始設置autosizing :

Autosizing top-left view

這一步使View能緊挨着頂部和左邊緣(而不是底部與右邊緣),並且在水平和垂直方向上都能夠支持伸縮當superview改變其大小時。

類似地, 改變 右上角autosizing 設置:

Autosizing top-right view

這是底部view的設置:

Autosizing bottom view

運行程序並且轉動設備至景觀方向。現在應該看上去是這樣:

Landscape looks bad (2)

和理想的很接近了,但是還有點瑕疵。三個view之間的距離是不正確的。另外仔細看,這三個view的尺寸也不是100%正確. 造成這個原因是autosizing masks雖然知道要改變view的尺寸當superview改變時,但是它不知道具體該改變多少尺寸。

你可以玩一下 autosizing masks-比如說,改變可以改變的寬和高的值(“springs”)- 但是你幾乎不可能精確設置到20-points的距離在三個view之間。

Why?!?!?

爲了解決使用 the springs and struts 方式改變佈局所造成的問題,很不幸的,你必須要寫一些代碼來做。

UIKit 會發送一些消息到你的view controllers當用戶界面在開始旋轉前,在旋轉過程中以及旋轉後。你可以通過監聽這些消息來改變你用戶界面的佈局。通常你會重寫willAnimateRotationToInterfaceOrientation:duration: 來改變任何需要重新規劃的view的frame。

但在你開始做這之前, 你首先需要聲明views裏面的outlet 屬性。

Xcode切換到 the Assistant Editor 模式(在Xcode工具欄的右上角的編輯器工具包的中間一個按鈕)然後把每個view拖拉至view controller:

Ctrl-drag outlet property

逐個把這些view與屬性連接起來:

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

Add the following code to ViewController.m:

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 
                                         duration:(NSTimeInterval)duration
{
    [super willAnimateRotationToInterfaceOrientation:toInterfaceOrientation duration:duration];

    if (toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft
    ||  toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
    {
        CGRect rect = self.topLeftView.frame;
        rect.size.width = 210;
        rect.size.height = 120;
        self.topLeftView.frame = rect;

        rect = self.topRightView.frame;
        rect.origin.x = 250;
        rect.size.width = 210;
        rect.size.height = 120;
        self.topRightView.frame = rect;

        rect = self.bottomView.frame;
        rect.origin.y = 160;
        rect.size.width = 440;
        rect.size.height = 120;
        self.bottomView.frame = rect;
    }
    else
    {
        CGRect rect = self.topLeftView.frame;
        rect.size.width = 130;
        rect.size.height = 200;
        self.topLeftView.frame = rect;

        rect = self.topRightView.frame;
        rect.origin.x = 170;
        rect.size.width = 130;
        rect.size.height = 200;
        self.topRightView.frame = rect;

        rect = self.bottomView.frame;
        rect.origin.y = 240;
        rect.size.width = 280;
        rect.size.height = 200;
        self.bottomView.frame = rect;
    }
}

當view controller旋轉至一個新的方向時會調用這個回調函數。現在當用戶界面的方向轉動時view controller使它裏面的view尺寸縮放理想了- 這是一種建立在對iPhone屏幕尺寸瞭解上的硬編碼能力。因爲這個回調函數發生在一個動畫block裏,所以當改變它的尺寸會有動畫效果。

等等,現在還不能運行程序。 你必須先恢復這三個view的autosizing masks 設置如下圖所示,否則 autosizing 機制會與你在 willAnimateRotation: 函數設置裏的view的位置、尺寸產生衝突。

Autosizing off

現在可以運行程序了,然後將設備翻轉至景觀方向。可以看到每個view的呈現都很理想,再次翻準屏幕至肖像方向,看上去也還不錯。

這樣做成功了,但是爲了這麼個簡單的呈現你就要必須寫許多代碼了。想象一下,當你遇到真正更加複雜,特別是動態的那些獨立View改變尺寸,或者有一系列的subviews沒有被固定時你在代碼上所需要作出的努力。

There must be another way

提示: 你還可以使用另外一種方法,那就是同時做好肖像方向以及景觀方向的nib,然後當設備轉動時,把對應的view從nib文件載入進來,把當前的view交換出去。但即使這樣,你還是需要做很多的工作,另外你還多了同時管理兩個nib文件而不是一個nib文件的麻煩。

Auto Layout 來拯救了!

現在我將要展示的是如何用Auto Layout來做到同樣的效果。首先,把willAnimateRotationToInterfaceOrientation:duration:這個方法從ViewController.m裏面刪除,因爲目前我要做的Auto Layout是不需要寫任何代碼的。

回到ViewController.xib然後在File inspector控制面板裏,把“Use Autolayout”的複選框勾上使Auto Layout對這個nib文件起作用:

Enable autolayout

提示: Auto Layout 功能在整個nib或者storyboard文件裏總是被開啓着的。在這兩種文件裏的所有view都會使用Auto layout功能如果你把勾選上的話。

現在運行程序並且轉動屏幕,呈現的樣子還是之前的混亂樣。

Landscape looks bad

現在讓我們啓動Auto Layout功能. 按住Cmd鍵同時選中頂部的兩個view (綠色的以及黃色的),。 從 Xcode的Editor 菜單, 選擇PinWidths Equally:

Pin widths equally

再次重新選中這兩個view並且做 EditorPinHorizontal Spacing操作 (即使這兩個view看上去像被選中了當你做第一個Pin操作後。但是請注意目前他們處在一種特殊的佈局關係顯示模式中,你還是必須要重新選中這兩個view。)

在左邊的文檔概要圖中, 你會注意到有一個新的section名叫 “Constraints”. 這個section 會被自動加入當你在nib文件中啓用Auto Layout時。在這篇文檔的下一部分你會瞭解到這些Contraints是什麼以及他們是如何操作的。

現在, 我們把一個名叫  “Horizontal Space (170)” 的從Constraints列表裏面刪除:

Horizontal space constraint

運行程序並轉動屏幕. 現在看上去好多了 – 頂部的兩個view 有了合適的寬度和間距 – 但還不是我們想要的樣子:

Landscape almost there

按住Cmd鍵同時選中所有的三個view。 在菜單欄, 做PinHeights Equally 操作

現在還是按住Cmd鍵同時選中左上角的以及底部的view,然後做EditorPinVertical Spacing 操作

最後,把“Vertical Space (240)” 從constraint列表裏面刪除。

如果你一下子同時選中所有的三個view,Interface Builder應該如下圖所示:

The constraints

藍色的T型狀對象定義了各個view之間的限制。這看上去有點複雜, 但是你一旦學會了,你會發現這種表達相當簡潔明瞭。

運行程序 … 哇, 沒有寫一行代碼每樣東西都看上去非常棒了!

Landscape good

酷, 但剛纔你究竟做了什麼呢?Auto Layout 能使你簡單地表達清楚頁面佈局中的各個view之間的關係而不會讓你爲了各種view有多大以及他們該定位在哪裏硬編許多代碼 。

你剛纔做了如下的關係操作 – 也就是 constraints – 在頁面佈局裏:

  • 左上角和右上角的view (也就是第一次的pin widths equally 操作).
  • 在左上角view和右上角view之間有20-point的間距 (相應的操作是 pin horizontal spacing).
  • 所有的view是相同的高度 (相應的操作是pin heights equally).
  • 在頂部兩個view與底部的view之間有一個20-point的間距 (the pin vertical spacing).

以上這些就足以展示,當屏幕尺寸變化時,Auto Layout如何放置佈局裏的各種view以及它是如何工作的。

Well done

提示: springs-and-struts佈局模式也會帶來一些其他限制當你從它切換至“Use Autolayout”模式時。對於各個view和屏幕邊緣之間的邊距都基本會有一條限制,是這麼說的:“這個view總是和頂部/底部/左邊/右邊保持着20-points的距離。”

你可以看到你的所有contraints在文檔概要裏。如果你在文檔概要裏點擊一個constraint,Interface Builder會在contraint在view中所體現的地方通過畫一條白色的邊框並且對之添加一個陰影使其高亮顯示:

Selected constraint

Constraints是真實的對象 (屬於 NSLayoutConstraint類) ,他們也擁有相應的屬性。 比如說,選中頂部兩個view間距的constraint(名爲“Horizontal Space (20)”)然後切換至它的Attributes inspector。 現在你可以通過修改Constant裏的值來改變兩個view之間的距離大小。

Constraint attributes

將之設置成100並且運行程序。現在兩個view之間的距離更寬了:

Landscape wider margin

當你的程序需要描述各種view的佈局時,Auto Layout比起springs and struts表達能力要強許多。在這份教程的餘下部分,你將會學到關於constraints的所有以及如何在Interface Builder應用之並使其能做到各種佈局安排。

Auto Layout的工作原理

就像你在上面看到的測試一樣, Auto Layout 的基本工具就是constraint. 一個constraint 描述了兩個view之間的幾何關係。比如說,你可能有一個constraint是這樣的:

“Lable A的右邊界和和Lable B的左邊界以20 points的空白相連接。”

Auto Layout用所有的這些constraints來對你所有的view做一些數學計算以致view達到一個理想的位置以及尺寸。 你不再需要自己來設置view的frame-Auto Layout會幫你做這一切-完全基於你對view所設置的constraints。

在沒有Auto Layout之前,你總是通過硬編碼來設置view的框架, 也可能通過Interface Builder 座標裏面精確的放置他們,通過initWithFrame:來傳遞一個矩形,或者通過設置view的frame,bounds或者center 屬性。

對於剛剛你做的應用, 你特地把frames設置到下圖所示:

Struts coordinates

你也可以對每個view做autosizing masks設置:

Struts autosizing masks

那應該不再是你認爲的屏幕設計方式了。使用Auto Layout,你所要做的只是如下圖所示:

Auto Layout instead of struts

現在對於view來說尺寸和位置已經不那麼重要了; 把問題都交給constraints吧。當然, 當你在canvas裏拖進一個新的按鈕或者標籤時,這個控件會有一個特定的尺寸然後你把它放到一個特定的位置, 但這也只是一種設計目的來告訴Interface Builder在哪裏放置constraints。

設計成你想要的樣子

對你來說一個巨大的優勢來使用constraints是你不再需要擺弄座標系統來使你的各個view出現在合適的位置。你要做的只是通過對Auto Layout描述每個view之間的聯繫關係。這種設計方式我們叫做 通過目的來設計.

當你通過目的來設計時, 你在表達的是你想要達到的目標是什麼而不是如何來完成目標。在以前會是這麼個說法:“這個按鈕的左上角的座標是(20, 230)”, 現在你可以這麼表達了:

“這個按鈕在它的superview中垂直居中,把他放置在離它的superview左邊緣的一個固定位置。”

使用這個描述, Auto Layout能自動計算出你的按鈕該出現在哪裏, 無論它的superview的大小。

這裏是其他通過目的來設計的例子(Auto Layout 能夠應付所有的這些指示):

“這兩個text fields應該保持同樣大小。”
“這兩個button應該保持同時移動。”
“這四個標籤應該同時保持右邊對齊。”

這就使你的用戶界面設計顯得更加具有描述性。你只需簡單的定義constraints, 然後系統會自動幫你計算frames。

在第一部分你看到了,要想讓一個只有幾個view的頁面佈局同時在iPhone的兩個方向顯示的合適所需要做到的很多工作。但如果你用Auto Layout來做的話就可以省去那一方面的力氣了。如果你對constraints設置的恰當,那麼佈局會自動恰當顯示而不需要你對肖像方向和景觀方向的view做一絲變化。

對於使用Auto Layout另外個重要的好處是國際化。 比如說德文字符, 是出了名的長,把它放進你的標籤會是一件十分頭疼的事情。 但是再一次,Auto Layout會來拯救你,因爲它能夠幫你自動縮放基於內容需要表現的標籤-除此以外的每樣東西還是會根據constraints來調整。

添加對德文, 法文, 以及其他的語言的支持要做的只是簡單設置你的constraints ,translating the text,僅僅是這樣哦!

French

Auto Layout 最好的入門方式就是和它玩。這也就是這份教程餘下部分要講到的。

提示: Auto Layout is 不僅僅對方向旋轉有幫助;它也能很簡單的拉昇你的用戶界面來適應不同的屏幕尺寸。這不是一個巧合嗎!當iPhone 5的長屏幕出現時這項技術正好被加進了ISO裏 了。 Auto Layout 使得你在填滿iPhone 5的多餘垂直屏幕內容時變得非常簡單。並且天知道會不會有一個傳言中的 “iPad mini”出現… 至少你現在可以用Auto Layout 來爲將來做準備了。

愛上constraints

關掉你目前的工程然後創建一個新的項目使用Single View Application模板。命名項目爲“Constraints”。然後選擇爲iPhone project並且不使用storyboards,但是我們需要用到ARC。

一個使用Xcode4.5創建的新項目會默認爲你選擇啓動Auto Layout,所以你必要做任何特別的事情來啓用它。

點擊ViewController.xib 來打開Interface Builder。把一個新的圓角按鈕拖進canvas。 注意當你拖拽的時候,藍色虛線會出現。這些線被認爲是 guides:

Guides

這些guides會顯示在屏幕的頁邊, 也會顯示在中心:

Other guides

如果你之前使用過Interface Builder,那你毫無疑問會對這些guides很熟悉。當你想要對其東西時他們會非常有幫助。而當Auto Layout 啓用時,這些guides有了不同的意義。你當然還是需要他們來幫你對其東西,但同時他們也會告訴你新的constraints會體現在哪裏。

把button對着guides放到左上角。 現在的nib文件會看上去像這樣:

Button with guides

看,有兩個藍色的東西附屬在按鈕上。 這些 T型狀對象就是設置在這個按鈕上的constraint。

所有的constraints 也都列在Interface Builder的左邊的文檔概要面板裏:

Button constraints in document outline

目前我們有兩個constraints, 在button和main view的左邊緣之間有一個Horizontal Space, 在button和main view的頂部有一個Vertical Space。這層關係被constraint表示爲:

“這個按鈕會一直待在它的superview的左上角。”

現在再次選中這個按鈕並把它放到nib文件右上角,還是對着藍色guides:

Button top-right corner

現在 Horizontal Space 的constraint值改變了。它不再依附在按鈕的左邊界而是右邊界了。

當你對着guides放置一個按鈕(或者其他什麼view)的時候,你會得到一個標準的大小,這個是被定義在“HIG”裏面,這是蘋果公司的iOS Human Interface Guidelines文檔。對於屏幕的邊緣的頁邊距,標準的大小是20-points的空白。

甚至假設你把button放在某些沒有guide的地方,你還是會得到一個Horizontal or Vertical Space的constraint。試一下。然後把按鈕像左挪一點,得到如圖所示的效果:

Button larger H space

目前還是有一個 Horizontal Space的constraint。在文檔概要圖裏,你能看到現在沒有一個標準space了。

Larger H space document outline

你的按鈕放在哪裏,你就會得到一個對應的constraint。

還有一個“center”的constraint.。把按鈕拖到canvas的底部中心處,讓他正好能卡到中心guides:

Button bottom center

請注意這個Horizontal Space constraint現在被一個Center X Alignment constraint取代了,這也就意味着這個按鈕會一直跟着它的superview中心對其在水平軸上。依然有一個Vertical Space constraint值保持着這個按鈕待在view的最底部。(還是請使用標準頁邊距)。

運行程序並且轉動設備至景觀方向。看,甚至在景觀方向,這個按鈕還是呆在底部的中心位置:

Button at bottom center in landscape

對於這個按鈕,這是你想要表達的目的是: “這個按鈕應該一直待在底部的中心位置。” 請注意,現在沒有任何地方你必須要告訴Interface Builder你的按鈕的座標是什麼, 你只要把它放置的view中就行了。

有個Auto Layout,你可以不用在關心你的view在canvas裏面的精確座標位置了。所有這一切,Auto Layout會幫你從你設置的constraints裏面派生出來(或者說是Interface Builder爲你設置了這一切)。

在這個範例裏你可以看出這個按鈕在Size inspector裏面的轉化,那是相當的大啊:

Different size inspectors

當Auto Layout 禁用時,在X,Y,Width或者Height裏的值會改變所選中view的位置以及尺寸。當Auto Layout 啓用時,你還是能夠在這些框裏面輸入新的值,但通常結果不會你是想要的效果。那個view 會移動,但是Interface Builder也會基於你的新值來計算出新的constraints。

比如說,把Width的值改到100,canvas裏面的按鈕會變成下圖這個樣子:

Button with fixed width

現在 Center X Alignment constraint的值消失了, 取而代之的是一個把按鈕連在屏幕左邊緣的Horizontal Space,這個按鈕同時也會產生了一個新的constraint,它強制使按鈕的寬度固定在100 points(可以看到按鈕下方的藍色欄)。

你在文檔概要圖的左邊看到現在有了一個新的Width constraint:

Width constraint document outline

不像其他的constraint,那些是在按鈕和它的superview之間,這個寬度constraint只能應用於按鈕本身。你可以認爲它是一個按鈕和按鈕之間的constraint。

拖動按鈕使它再次卡在 Center X Alignment constraint 上。

小貼士: 因爲通過 Size inspector來改變位置和大小可能會搞亂你的constraints,我建議儘量不要這麼做,如果你非要改動佈局,請更改constraints。

你現在可能想知道爲什麼按鈕之前沒有一個Width constraint。在沒有的情況下,Auto Layout是如何知道要改變按鈕的長度的呢?

可以這麼解釋:這個按鈕自身知道他的寬度應該是多少,它通過基於它裏面的標題文字外加上一些圓角的邊距填充,可以計算出來的。如果你設置了一個按鈕的背景圖片,它也會把這一點計算在內的。

這個現象被認爲是固有內容尺寸。不是所有的空間都會這樣,但是大部分是這樣的(UILable不在內)。如果一個view能夠計算出它自己的首選尺寸,那麼你就沒有必要對其專門設置Width or Height constraints 了。關於這個以後你就看得多了。

I am not fat

爲了得到按鈕的最佳尺寸,選中它並且在Editor菜單裏將至設置爲Size to Fit Content 。這步操作會使按鈕擺脫明確的Width constraint 並且將之恢復爲按鈕的固有內容尺寸模式。

兩個按鈕的探戈

Guides 不僅可以出現在view與superview的, 也可以出現在同一階層的多個view之間。爲了證明這點,現在請在canvas裏面拖進一個新的圓角矩形按鈕。

如果你把這個按鈕放得離另外一個比較遠,這個按鈕回得到自己的constraints。然而,如果你把兩個按鈕放的足夠近,那麼這兩個按鈕的constraint會開始互相作用。

把新的按鈕捕捉到原來按鈕的旁邊:

Snap two buttons

現在這裏會出現一些點狀guidelines,但Interface Builder不會把他們全部轉換成constraint;因爲這有一點多了。但這基本會認出這兩個按鈕能在各個方位對齊-在他們的頂部,中心以及基線處。

在把新按鈕放下後,這個按鈕的constraints會看上去像這樣:

Two buttons

如圖所示,新的按鈕有一個Vertical Space對於屏幕的底部,也有一個Horizontal Space對於另外一個按鈕。但是這個space是非常小的(只有8points),T型狀對象可能很難看到,但一定是存在於那裏的。

在文檔概要圖中選中Horizontal Space constraint :

Highlighted H-space between buttons

當你選中一個constraint的時候,它會在屏幕中屬於它的地方高亮顯示。這個顯示在兩個按鈕之間特別的constraint ,它的意思是在說:

“第二個按鈕將會一直出現在第一個按鈕的右邊,無論第一個按鈕的位置以及大小如何變化。”

選中左邊的按鈕然後輸入一些字比如說“A longer label”。你會看到當新的標題輸進去以後,左邊的按鈕重新設置了其尺寸,並且另外一個按鈕也移出了它原來的位置。但是它始終是附屬在第一個按鈕的右邊邊界,這也就是我們想要的結果:

Button with longer label

請注意Interface Builder重新用一個Horizontal Space代替了原來的Center X Alignment。每次當你對控件做一個尺寸的(或者位置)的改變,Interface Builder會計算出一個它認爲對的constraint。通常來說,它都是對的,但有時候它會完全誤解我們的意思。在這裏,你明顯想要將按鈕保持在中心位置當你在改變其中的文字時。

把按鈕重新放置到它的中心對齊處去。看看現在的constraint是怎麼樣的:

Two buttons disconnected

這可能不是你想要發生的。現在兩個按鈕之間不再互相連接了。取而代之的是,新的右按鈕和屏幕的右邊緣有了一個Horizontal Space的constraint。兩個按鈕之間沒有Horizontal Space了。

當然,你可以通過把捕捉在一起然後再將他們重新連接,但這個問題是可以通過不拖拽view來避免的。

首先,通過快捷鍵Cmd-Z來取消操作,使第一個按鈕不再中心對齊。現在選中按鈕並且在Editor 菜單選擇 AlignHorizontal Center in Container。這次不僅是第一個按鈕移到了屏幕的中心處-另外一個也跟着移了過來。更可能應該這樣操作吧!

爲了能夠對之概念有更好的瞭解,還是多做一些操作吧。選中小的按鈕然後把它放到大的上面去,這樣以來他們被捕捉進了place vertically(但不要嘗試對齊這兩個按鈕的左邊緣):

Button on top

因爲你把兩個按鈕捕捉在了一起,所以現在他們之間有一個Vertical Space。這個間距依然是由HIG推薦的8 points遠。

提示: 這個 “HIG”, 是 iOS Human Interface Guidelines的簡稱, 介紹了蘋果對設計優秀的用戶界面推薦設置。對於IOS開發人員來說是必讀的.。HIG 解釋了在哪種情況下選擇哪種UI元素是合適的,並且提供使用他們的最好實例. 你可以在這裏查看它。

你可以對於控件之間的標準距離不受限制。constraint是完全成熟的對象,就像view,所以你也可以改變其屬性。

選擇兩個view之間的Vertical Space constraint。你也可以通過點擊T型狀對象來做到,儘管這有點太過講究。但目前爲止最簡單的方式還是點擊文檔概要圖裏面的constraint。一旦你選中了,切換到Attributes inspector:

V-space attributes

默認的Standard attribute的勾是選上的。對於兩個對象之間的space constraint是8 points;對於一個view於之superview之間的邊緣距是20 points。在constraint框裏面輸入40來改變其constraint大小。看,現在兩個按鈕離的更遠了,但他們之間還是連接着的:

V-space larger

運行程序來看看效果:

V-space larger landscape

按鈕之間明顯保持着他們的垂直距離安排,但是他們的水平方向卻沒有!

如果你仔細看nib文件,你會發現上邊的按鈕和canvas的左邊緣之間有一個Horizontal Space(如果你像我一樣在同一個點粗糙的放置了那個按鈕的話):

H-space anchoring top button

底部的標籤在屏幕中水平居中對齊,但上邊的按鈕不是的-它總是和左邊緣保持着一樣的距離。

這看上不是很理想,其實你想要的結果是如下目標:

“底部按鈕應該一直保持水平居中,並且頂部按鈕左邊界要一直對齊着底部按鈕的左邊界。”

對於第一中constraint,你已經擁有了,但是第二種你還沒有。Interface Builder 會顯示對齊的guides, 所以你能夠向左拖拽上邊的按鈕直到它的邊界捕捉到下邊的邊界:

Snap left edges

不幸的是,這個操作移出了兩個按鈕之間的Vertical Space(至少在有些時候,這取決於控件是如何拖拽以及放置的操作)。Interface Builder根本“忘了”那曾經有一個Vertical Space,取而代之的操作是於底部的view又重新生成一個Vertical Space:

Two buttons left aligned, wrong V-space

這和你想要的結果差的太遠了。結果不應該是在兩個按鈕之間有一個Vertical Space 嗎?而不是窗口的底部產生一個Vertical Space。這個漫畫可以表達你的心情當這一切發生時。


發佈了151 篇原創文章 · 獲贊 12 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章