Storyboard 自適應佈局

原文鏈接:http://justsee.iteye.com/blog/2148987

通用的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處於容器居中的位置,並且它的頂部與容器頂部有一個固定的間距。現在我們需要添加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 圖片,按下空格:



 

現在將 [email protected] 圖片拖至 2x 圖片區域,將 [email protected] 圖片拖至 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 確實是一項重大改進,是程序員和設計人員的福音!

由於本文的示例是一個天氣應用,所以光有天氣圖標不行,我們還得加上城市和溫度才行。

 

 

給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下的橫屏、豎屏是多麼的完美:



 


 

 

 

 

via:http://www.devtalking.com/articles/adaptive-layout-1/

http://www.raywenderlich.com/83276/beginning-adaptive-layout-tutorial

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章