適配iPad和iPhone

咱們打開Xcode,新建一個項目:git



 

選擇iOS\Application\Single View Application建立一個單視圖應用:程序員



 

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



 

建立好項目後,咱們在項目目錄結構中能夠看到只存在一個storyboard文件:編輯器



 

Main.storyboard文件就是一個通用的storyboard文件,它能夠適配目前全部屏幕尺寸的Apple移動設備。打開該文件,同窗們會看到一個View Controller,以及一個咱們不太熟悉的界面尺寸:ide



 

同窗們不要吃驚,沒錯,大家看到的就是一個簡單的、有點大的正方形!大夥都知道,在上一個版本的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處於容器居中的位置,而且它的頂部與容器頂部有一個固定的間距。如今咱們須要添加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、iPhone六、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 確實是一項重大改進,是程序員和設計人員的福音!

因爲本文的示例是一個天氣應用,因此光有天氣圖標不行,咱們還得加上城市和溫度才行。

 

 

給TextContainer中添加內容

打開 Main.storyboard ,從組件庫(Object Library)中拖拽兩個 Label 組件到TextContainer中,位置能夠隨意擺放:



 

先選擇靠上的Label,而後點擊底部的 Align 按鈕,添加一個 Horizontal Center in Container約束,再點擊 Pin 按鈕,添加一個 Top Spacing to nearest neighbor 約束,設置其值爲10:



 


 

而後選擇右側工具欄中的 Attribute Inspector 頁籤,將該Label的 Text 屬性設置爲 CupertinoColor 屬性設置爲 White ,Font 屬性設置爲 Helvetica Neue, Thin , Size 屬性設置爲 150

這時同窗們可能會發現基本看不到剛纔設置的文字的全貌,這是由於Label大小的緣由。彆着急,咱們很快就會解決這個問題。

如今選擇另外一個Label,按照上述的方法給它也添加一個 Horizontal Center in Container 約束以及一個 Bottom Spacing to nearest neighbor 約束,將其值設置爲10。打開右側工具欄中的 Size Inspector 看看:



 

而後選擇 Attribute Inspector 將該Label的 Text 屬性設置爲 28C , Color 屬性設置爲 White, 將 Font 屬性設置爲 Helvetica Neue, Thin, 將 Size 屬性設置爲 250

如今是時候解決Label大小的問題了。選中view controller的view,點擊底部的 Resolve Auto Layout Issues 按鈕,在彈出菜單中選擇 All Views\Update Frames ,如今看看storyboard中發生了什麼:



 

咱們看到了剛纔設置的城市和溫度,可是他們有一點點重疊,這可不是咱們想要的結果。在咱們修改這個問題以前,先看看預覽編輯區的顯示狀況。咱們發如今iPad下顯示貌似還挺完美:



 

可是在iPhone下不出所料的沒法直視,字體太大了:



 

接下來讓咱們解決這個重疊和字體大小的問題。

Size Classes

通用的storyboard文件當然很好,可是你想真正把它玩轉仍是得花功夫去研究它,這是一件頗有挑戰性的工做,固然咱們也要懂得運用一些現有的工具來幫助咱們。Xcode6就爲咱們提供了一些工具和技巧,幫助咱們更好的實現自適應佈局。

自適應佈局有一個很重要的概念就是 Size Classes。它並不表明真正的尺寸,而是咱們從感官上感受尺寸的種類,經過這種種類的組合,表示出不一樣屏幕尺寸設備的橫屏及豎屏。

Xcode6爲咱們提供了兩個種類:普通(Regular)和緊湊(Compact)。雖然它們涉及到視圖的物理尺寸,但通常它們只表明視圖的語義尺寸,即不是真正的尺寸,而是咱們從感官上分出的尺寸種類。

下面這個表格向同窗們展現了size classes和各個尺寸設備豎屏、橫屏之間的關係:



 

上表中的這些size classes組合都是咱們在開發應用中常常碰到的。然而你也能夠在視圖的任何一個層級中覆蓋這些size classes。當之後咱們開發Apple Watch應用時顯得尤爲有用。

Size Classes與開發者

何爲設計應用的UI?雖然如今大家的應用已經知道要使用Size Classes,而且大家在storyboard文件中設計應用界面時已經拋開了具體尺寸大小的束縛。可是大家難道沒有發如今全部尺寸的設備中,不論是豎屏仍是橫屏,應用的界面佈局都是一致的嗎?只是自適應了尺寸大小而已。這還遠遠不是設計。

當大家決心要設計自適應的界面並已經開始設計的時候,有一點很關鍵。那就是要知道界面在不一樣的Size Classes要有繼承的關係。大家應該首先設計一個基礎的界面,而後根據不一樣尺寸的橫豎屏在基礎的界面上進行自定義。千萬不要把不一樣的Size Classes當作獨立的屏幕尺寸去設計UI。應該在大家的腦海中創建起界面的一個繼承關係的思想,也就是大多數的設備使用基礎界面,而後特別的尺寸及橫豎屏再根據狀況基於基礎界面修改。

在本文中,一直沒有像你們介紹過如何設置特殊設備的佈局,那是應爲自適應佈局的核心概念Size Classes自己就是由各類特殊設備的特色抽象而來的。也就是說一個Size Classes就意味着一種特殊設備的佈局特色,其實普通狀況也是特殊狀況中的一種。因此說咱們能夠組合不一樣的Size Classes來知足各類特殊的佈局狀況,好比一個支持自適應的視圖,它能夠在應用的父視圖控制器中自適應,也能夠在某一個功能的視圖控制器容器中自適應。可是二者自適應後的佈局卻不相同。

這種改進對Apple自己也是有益的,由於他們不斷的改變移動設備的尺寸,但歷來沒有強迫開發者和設計者從新開發和設計他們的應用以適應新尺寸的設備。這就不會讓開發者和設計者對Apple不斷改變設備尺寸這件事有抗拒心理。

接下來,咱們將自定義Size Classes以適應iPhone橫屏的時候,由於如今的佈局在橫屏時用戶體驗很糟糕。

使用Size Classes

回到 Main.storyboard,點擊底部的 w Any h Any,你就能夠看到Size Classes的選擇器了:



 

在這個由9個方格組成的網格中,你就能夠選擇你想在storyboard中顯示的Size Class。一共有9種組合方式:3種垂直的也就是豎屏的(任意尺寸(Any),普通(regular),緊湊(compact))選擇和3種水平的也就是橫屏(任意尺寸(Any),普通(regular),緊湊(compact))的選擇。

注意:這裏有一點須要你們注意。在Size Classes中,有兩個重要的概念叫作水平(Horizontal)垂直(Vertical)。可是在IB中叫作 寬(Width)高(Height)。但他們是等價的,因此你們記住這個概念有兩種叫法就能夠了。

目前咱們的佈局在緊湊高度(Compact Height)時顯示的很糟糕,也就是iPhone橫屏時。咱們來解決這個問題,在Size Classes選擇器中選擇 Any Width | Compact Height 的組合:



 

這時你會發如今storyboard中會當即出現2個變化:



 

  1. storyboard中的view controller變成了咱們剛纔設置的size class。

  2. storyboard底部會出現藍色的長條區域,並顯示出當前咱們正在使用的size class。

爲了在該size class下改變佈局,咱們要臨時改變一些以前設置好的約束。在自動佈局中這種操做有個術語叫作 裝配(installing) 和 卸載(uninstalling) 約束。當一個約束在當前的size class中是適用的,咱們就將該約束裝配在當前的size class中,若是不適用,咱們就卸載它。

選擇image view,在右側工具欄中選擇 Size Inspector。你能夠看到在image view上添加的全部約束:



 

單擊鼠標左鍵選擇 Align Center X to: Superview 約束,而後按下鍵盤上的 Delete 鍵來卸載該約束。這時咱們能夠看到在storyboard中這個約束就當即消失了,而且在storyboard的結構目中和 Size Inspector中該約束都變成了灰色:



 


 

注意:你能夠在Size Inspector中點擊 All 來查看當前size class卸載掉的約束。

鼠標雙擊剛纔卸載的那條約束,咱們能夠看到在約束編輯界面的底部出現了額外的2個選項:



 

這兩個選項的意思就是這條約束在基礎佈局中是可用的,但在當前的 Any Width | Compact Height 佈局中是不可用的。

按照上面的步驟卸載掉image view上的另外3個約束:



 


 

如今你就能夠添加適合當前size class的約束了。咱們添加一個 Align/Vertical Center in Container 約束,再添加一個 Pin/Left Spacing to nearest neighbor 約束,其值設置爲10:



 


 

選擇image view,按住 Ctrl 鍵從image view上拖拽至view controller的view上,在彈出的菜單中選擇 Equal Widths 約束。

打開右側工具欄中的 Size Inspector 頁籤,雙擊 Equal Width to: Superview 打開該約束的屬性編輯界面。若是 First Item 屬性的值不是 cloud.Width ,那麼點擊輸入框,在下拉菜單中選擇 Reverse First and Second Item。而後將 Multiplier 屬性的值設置爲 0.45

如今image view在全部的size class中顯示應該都沒有什麼問題了。可是text container view還有點問題。你須要給它添加一個約束,讓它顯示在該size class屏幕的右側。

TextContainer view如今有兩種約束在身。一種是內部約束,它約束了兩個Label的位置,這些約束在各size class中表現的還不錯。另外一種是外部的約束,它們限制了text container view的左、右、底部與它容器的左、右、底部的間距。這些約束在當前的size class中表現的就不盡如人意了。若是想使text container view在當前size class中位於容器的右下角位置,你得卸載掉左側的約束。

選中 Left Spacing to nearest neighbor 約束:



 

按 Cmd-Delete 卸載該約束,和以前同樣,被卸載的約束顯示爲灰色。

如今你須要再添加兩個約束將TextContainer限制在正確的位置上。一個是讓text container view的寬度爲它容器(view controller的view)寬度的一半。另外一個是將text container view固定在頂部。

按理來講,你如今須要選中text container view而後按住Ctrl鍵和鼠標左鍵拖動鼠標到view controller view上,而後選擇約束。可是目前的狀況因爲image view和text container view佔滿了整個view controller,因此你很難選中view controller的view。同窗們能夠經過storyboard的結構樹上進行該操做,會容易不少。

在結構樹中選中TextContainer,按住 Ctrl 鍵和鼠標左鍵,拖動鼠標到結構樹的View上:



 

彈出菜單中顯示了可用的約束,按住 Shift 鍵點擊 Top Space to Top Layout Guide 和 Equal Widths 約束:



 

而後選中TextContainer,在 Size Inspector 中設置剛剛添加的兩個約束:

  • 將 Top Space to: Top Layout Guide 約束的值設置爲0。

  • 將 Equal Width 約束的 Multiplier 的值設置爲0.5。這裏要注意 First Item 和 Second Item 這兩個屬性的值。前者應爲TextContainer view,後者爲view controller view。若是不一致,那麼點擊任意一個輸入框,選擇 Reverse First and Second Item

如今點擊storyboard界面底部的 Resolve Auto Layout Issues 按鈕,而後選擇 All Views\Update frames 。看看發生了什麼變化呢:



 

到目前爲止,咱們的佈局已經愈來愈接近完美了,惟一一點不足的就是字體大小的自適應,咱們會在下一節解決它!

文字屬性的自適應

目前TextContainer中的文字尺寸在iPad設備上,也就是使用普通(Regular)size class顯示還比較正常。可是當使用緊湊(Compact)size class時文字尺寸就顯得太大了,以致於都超出了視圖。不過同窗們不要怕,咱們照樣能夠在不一樣的Size Classes中設置不一樣的文字尺寸來作到自適應。

注意:與重寫佈局不一樣,在不一樣的size class中改變文字的屬性始終會影響基礎佈局中的文字。它不能像佈局同樣,在不一樣的size class中設置不一樣的屬性值。咱們經過下面的方法來解決這一問題。

回到storyboard文件中,將目前的size class改成最基礎的 Any Width | Any Height 。

選擇顯示Cupertino的Label,打開 Attribute Inspector 。點擊 Font 屬性前面的 + 號:



 

彈出的菜單內容是讓咱們選擇一種size class的組合來重寫該組合下的文字屬性。咱們選擇Compact Width > Any Height



 

這時就會出現另一個文字屬性下拉框,針對於咱們剛纔選擇的 Compact Width | Any Height size class,咱們將字體大小改成90:



 

再選擇顯示溫度的Label,重複剛纔的操做,選擇size class組合時選擇 Compact Width > Any Height。設置字體大小爲150。

在預覽區域會自動更新咱們剛纔的設置:



 

如今看起來稍微好一些了,可是顯示 Cupertino 的Label被截掉了兩頭。同窗們可能會繼續調整字體大小使Cupertino顯示徹底,雖然目前看起來完美了,可是當換一個城市名稱後或許又會出現剛纔的問題。好比Washington, D.C這麼長的名稱,又好比Kleinfeltersville, PA這個更長的名稱。那麼咱們應該如何設計呢?

咱們的救世主 自動佈局(Auto Layout) 再次出馬。你只須要給顯示城市名稱和溫度的這兩個Label設置一個相對於TextContainer view的寬度約束便可。選中顯示Cupertino的Label,按住 Ctrl 鍵和鼠標左鍵,拖動鼠標到TextContainer view,在彈出菜單中選擇 Equal Widths 約束。對顯示溫度的Label作相同的操做。以後在預覽界面看看發生了什麼:



 

呃……貌似仍是有問題,城市名顯示不徹底。Label中的文字長度超出了容許顯示的空間。不過咱們能夠經過一個選項,讓Label自動判斷當前的空間能夠顯示多大的字體。

選擇顯示Cupertino的Label,而後打開 Attribute Inspector。將 AutoShrink 屬性設置爲Minimum font scale,將其值設置爲0.5。將 Alignment 屬性設置爲 Centered



 

對顯示溫度的Label作相同的操做。

再來看看預覽區域,是否是在不一樣尺寸的iPhone橫屏、豎屏下顯示都比較完美了:



 

是時候在不一樣的設備上編譯運行咱們的程序了。用設備來檢驗纔是最保險的。iPhone下的橫屏、豎屏是多麼的完美:



 


 

詳細介紹:https://github.com/shengguoqiang/AutoLayout-Size-Classes.git