通用的Storyboard
通用的stroyboard
文件是通向自適應布局光明大道的第一步。在一個storyboard
文件中適配iPad和iPhone的布局在iOS8中已不再是夢想。我們不必再為不同尺寸的Apple移動設備創建不同的storyboard
文件,不用再苦逼的同步若干個storyboard
文件中的內容。這真是一件美好的事情。
我們打開Xcode,新建一個項目:

選擇iOS\Application\Single View Application
創建一個單視圖應用:

設置項目名稱AdaptiveWeather,語言選擇Swift,設備選擇Universal:

創建好項目后,我們在項目目錄結構中可以看到只存在一個storyboard
文件:

Main.storyboard文件就是一個通用的storyboard
文件,它可以適配目前所有屏幕尺寸的Apple移動設備。打開該文件,同學們會看到一個View Controller,以及一個我們不太熟悉的界面尺寸:

同學們不要吃驚,沒錯,你們看到的就是一個簡單的、有點大的正方形!大伙都知道,在上一個版本的Xcode中,storyboard
里的屏幕尺寸都對應著我們所選的目標設備的尺寸,但是這樣無法讓我們達到“用一個storyboard
搞定所有設備”的宏偉目標。所以在iOS8中,Apple將storyboard
中屏幕的尺寸進行了抽象處理,也就是說我們看到的這個正方形是一個抽象的屏幕尺寸。
我們接著往下走,選中Main.storyboard
文件,然后在右側工具欄中選擇File Inspector頁簽,然后勾選Use Size Classes選項:

在新的iOS8項目中,該選項默認是勾選的。但當你使用老版本的項目創建新的storyboard
文件時就需要你手動進行勾選了。
設置你的Storyboard文件
首先,我們打開Main.storyboard
文件,從組件庫(Object Library)中選擇Image View拖拽到View Controller中。選中剛剛拖入的Image View,在右側工具欄選擇Size Inspector頁簽,設置X坐標為150,Y坐標為20,寬為300,高為265。
然后再拖入一個View組件,設置X坐標為150,Y坐標為315,寬為300,高為265。
選擇你剛才拖入的View,在右側工具欄中選擇Identity Inspector頁簽,在Document面板中的Label屬性輸入框中輸入TextContainer。這個屬性的作用就是給View起一個名字,方便我們辨認。這里要注意一下,Document面板有可能是隱藏的,我們需要點擊它后面的 Show按鈕來顯示它。我們拖入的這個View最后是顯示城市和溫度Label的容器。

完成上面的設置后,同學們可能會發現剛才拖入的View貌似看不到,這是因為它的背景色和View Controller的背景色是相同的,都是白色,所以我們不太容易辨別。我們來解決這個問題,選中View Controller的View,然后在右側工具欄中選擇Attribute Inspector頁簽,設置背景色為 紅:74,綠:171,藍:247。然后再選擇TextContainer,就是我們拖入的View,設置背景色為 紅:55,綠:128,藍:186。此時Main.storyboard
文件中應該是這番景象:

到目前為止,我們在View Controller中添加了兩個組件Image View和View,這也是僅有的兩個組件,接下來我們就要給它們添加一些布局約束了。
添加布局約束
選擇image view,點擊底部自動布局工具欄中的Align按鈕,勾選Horizontal Center in Container選項,將后面的值設置為0,點擊 Add 1 Constraint按鈕添加第一個約束。

這個約束的意思是讓image view在它的容器(View Controller的View)中保持居中。
然后再點擊底部自動布局工具欄中的Pin按鈕,添加一個image view頂部與容器頂部間距的約束,我們設置為0:

上面這兩個約束使image view處于容器居中的位置,并且它的頂部與容器頂部有一個固定的間距?,F在我們需要添加image view和text container view之間的約束。同學們先選中image view,然后按住Ctrl鍵和鼠標左鍵,從image view往text container view移動鼠標:

松開鼠標左鍵后會彈出一個約束菜單,我們選擇Vertical Spacing:

這個約束決定了image view底部和text container view頂部之間的距離。
現在選中image view然后點擊右側工具欄中的Size Inspector頁簽,同學們會發現這里在Xcode6中和之前的Xcode版本有所不同:

你會看到之前添加的三個布局約束,你可以在Size Inspector中很方便的修改這些布局約束。比如點擊Bottom Space To: TextContainer約束后的 Edit按鈕,會彈出約束屬性編輯框,我們讓Constant的值等于20:

然后點擊該彈出框之外的任意地方關閉該彈出框。
你先已經將TextContainer view頂部與image view底部的間距調整到了20,我們還需要添加TextContainer view另外三個邊的間距約束。
繼續選擇TextContainer view,點擊底部的Pin按鈕彈出 Add New Constraints窗口,在 Spacing to nearest neighbor面板中設置左、右、底部的約束,將值設置為0,然后點擊Add 3 Constraints按鈕添加約束。這里要注意的是,在設置約束時要將 Constrain to margins選項的勾去掉,這樣可以避免TextContainer view產生內邊距:

這三個約束會讓TextContainer view的左、右、底部三個邊與容器的左、右、底部的間距始終為0。
現在Main.storyboard中應該是這番景象:

此時同學們應該會注意到在view上有幾個橘黃色的約束線,這意味著還有一些約束上的問題需要我們注意。不過在運行時storyboard
會自動更新view的大小來滿足它與容器的約束條件。我們也可以點擊底部 Resolve Auto Layout Issues 按鈕,在彈出框中選擇 All Views in View Controller/Update Frames 來修復提示的約束問題,但是如果我們這樣做,那么image view的尺寸就會壓縮成零,也就是會看不到image view。
這是因為我們的image view還有沒有任何內容,但是它有一個缺省的高和寬,并且值為0。進行自動布局的時候,如果被約束的view沒有實際的高和寬,那么會依照缺省的高和寬來滿足約束條件。
我們接著學習,在項目結構中打開 Images.xcassets ,然后點擊左下角的 +號,在彈出菜單中選擇 New Image Set:

雙擊左上角的 Image 標題將其改為 cloud :

我們剛才新建的這個image set其實就是若干圖片文件的一個集合,其中的每一個圖片都會對應一個特定的應用場景,也就是針對與不同分辨率的Apple移動設備。比如說,一個圖片集合可能會包含針對非視網膜、視網膜、視網膜高清三種分辨率的圖片。自從Xcode中的資源庫與UIKit完美結合后,在代碼中引入圖片時我們只需要寫圖片的名稱,程序在運行時會根據當前運行的設備自動選擇對應分辨率的圖片。
注意:如果你以前使用過通過資源庫管理圖片,那么你可能會發現在Xcode6中會有所不同。那就是3x圖片是怎么回事?
這個新的分片率是專為iPhone 6 Plus提供的。這意味著每一個點是由3個像素點組成,也就是說3x的圖片比1x圖片的像素多9倍。
目前你的圖片集合中還是空的,同學們可以在這里下載需要的圖片cloud_images.zip ,然后將圖片拖入剛才創建的名為cloud的圖片集合中,將 cloud_small.png圖片拖到 1x圖片區域:

由于我們的圖片背景顏色是透明的,所以在圖片集合中看到的都是白色的圖片。你可以選中某一個圖片,然后按下空格鍵來預覽圖片。比如選中 1x 圖片,按下空格:

現在將 cloud_small@2x.png 圖片拖至 2x 圖片區域,將 cloud_small@3x.png 圖片拖至 3x 圖片區域。和之前情況一樣,我們看到的只是白色的圖片,但我們可以通過空格鍵來預覽圖片集合中的圖片。
現在你就可以在image view中設置圖片了。我們回到 Main.storyboard 中,選中image view,在右側工具欄中選擇 Attribute Inspector 頁簽,將 Image View 面板中的 Image 屬性設置為 cloud,然后將 View 面板中的 Mode 屬性設置為 Aspect Fit :

現在你的Main.storyboard中應該是這番景象:

我們看到storyboard
中一直有橘黃色的約束提示,是時候讓我們來修復它們了。首先選中view controller的view:

然后點擊底部的 Resolve Auto Layout Issues 按鈕,在彈出菜單的 All Views in View Controller 面板中選擇 Update Frames :

這時,storyboard
會自動根據約束條件重新計算view的大小以滿足約束:

預覽助手編輯器(Preview Assistant Editor)
一般情況下,在這個時候我們應該會在iPad、iPhone4s、iPhone5s、iPhone6、iPhone6 Plus這幾個不同尺寸的設備上編譯運行程序,以便測試通用的storyboard
是否能在不同尺寸的設備上正確的自適應。但這確實是個體力活,一遍一遍的更改設備、編譯、運行,多么苦逼。但上天總是會眷顧我們這些苦逼的程序員,Xcode6提供了Preview Assistant Editor,能在一個界面上顯示出不同尺寸設備的程序運行情況,是否有問題一目了然。
我們打開 Main.storyboard ,然后選擇 View\Assistant Editor\Show Assistant Editor ,這時編輯區會分隔為兩部分。再點擊頂部導航欄中的 Automatic ,在彈出菜單中選擇 Preview ,最后選擇 Main.storyboard (Preview) :

現在在 Assistant Editor 區域會顯示一個4寸的界面:

我們還可以點擊預覽界面底部,名字(比如圖中的iPhone 4-inch)旁邊的地方讓屏幕翻轉為橫屏:

這無疑是針對檢查不同尺寸設備的自適應情況的一項重大改進,但還遠遠不止于此!點擊預覽界面左下角的 + 按鈕,會彈出當前storyboard
文件支持的各種尺寸的設備,可供我們預覽:

分別選擇iPhone 5.5-inch和iPad,此時我們在預覽界面就可以同時顯示三種尺寸的屏幕:

此時同學們是否注意到4寸的橫屏顯示有點別扭呢?沒錯,它的那朵元太大了,我們可以通過對image view添加其他的約束條件來改善這個問題。
回到 Main.storyboard ,選擇image view,然后按住 Ctrl建和鼠標左鍵,拖動鼠標到View Controller的View上,松開鼠標后會彈出一個菜單,我們選擇 Equal Heights :

這時會出現一些紅色的約束提示,這是因為我們剛才加的這個約束條件與之前加過的約束條件有沖突。因為之前我們添加過image view和TextContainer view之間的垂直間距(Vertical Margins)約束,所以image view的高度不可能等于它容器(View Controller的View)的高度。
讓我們來修復該問題,首先在storyboard
的結構目錄中選擇我們剛才添加的 Equal Heights 約束,然后選擇右側工具欄中的 Attribute Inspect 頁簽,如果 First Item 屬性不是 cloud.Height ,那么在下拉菜單中選擇 Reverse First and Second Item 這一項讓 First Item 的值成為 cloud.Height :

接下來將 Relation 屬性的值設置為 Less Than or Equal ,將 Multiplier 的值設置為 0.4 :

這一系列設置的作用是讓cloud這張圖片的高度要么等于它自身的高度,要么等于屏幕高度的40%,最后呈現的效果選擇這兩者中較小的一個高度。
現在你應該注意到了在預覽面板中,4寸的橫屏顯示即時的對你剛才的約束改動做出了響應:

你看看其他尺寸的預覽自動更新了么?答案那是必須的,所以說 Preview Assistant Editor 確實是一項重大改進,是程序員和設計人員的福音!
由于本文的示例是一個天氣應用,所以光有天氣圖標不行,我們還得加上城市和溫度才行。