Apple從iOS 6加入了Auto Layout後開始就比較委婉的開始鼓勵、建議開發者使用自適應佈局,可是到目前爲止,我感受大多數開發者一直在迴避這個問題,無論是否是因爲歷史緣由形成的,至少他們在心底還堅守着固定佈局的老傳統思想。git
隨着iPhone六、iPhone6 Plus的到來,使用自適應佈局更是迫在眉睫的事,固定佈局的老傳統思想脆弱的不堪一擊。如今的iPhone有4種尺寸,若是算上iPad,如今Apple的iOS設備有5種尺寸。咱們在準備使用自適應佈局設計應用界面以前,能夠把這5種尺寸劃分爲3種分辨率和屏幕方向,這樣在設計時分類會更加清晰一些。iphone
咱們先來看一張自適應佈局的效果圖:編輯器
當大家學習完這篇文章後,大家應該會比較自如的使用 storyboard、constaints、size classes 這三個Apple在Xcode裏提供的工具,去探索和構建巧妙的自適應佈局。ide
Storyboards工具
在Xcode中,storyboard是一個可讓咱們對應用界面進行可視化佈局的工具,你首先能夠在storyboard文件中看到一個或若干個iOS設備屏幕大小的佈局區,而後你能夠從組件庫(Object Library)中拖拽組件到屏幕布局區中進行佈局(好比按鈕、圖片、文本框、labels等),你還能夠定義屏幕布局區之間的鏈接關係。佈局
用Xcode的術語來講,人們能夠看到、觸碰到或以其餘方式(按鈕、圖片、文本框、labels等)進行交互的用戶界面被稱爲views。屏幕中包含和管理這些views的容器稱爲view controller。性能
當咱們在storyboard中添加一個view controller後,咱們所看到的並非一個咱們熟知的屏幕尺寸,而是一個600X600的正方形:學習
從上圖咱們能夠很明顯的看出,storyboard中顯示的屏幕尺寸不是實際設備的尺寸。Apple這樣作的目的是將屏幕尺寸進行了抽象化,也就是說你能夠將這個正方形的屏幕當作iphone4的屏幕,也能夠將它當作iphone6的屏幕。動畫
模擬器的尺寸ui
當你習慣了600X600的屏幕後,你可能會用着很爽,可是有些時候,咱們也須要將它改爲實際的屏幕尺寸來設計一些東西。
咱們能夠很方便的在Xcode中改變view controller的模擬屏幕尺寸和屏幕方向:
佈局約束
介紹佈局約束的最好、最直觀的方法就是向大家展現一個示例。
首先咱們將storyboard中的屏幕布局區域的尺寸調整爲iphone5s的尺寸,也就是4寸屏幕,而後添加兩個正方形的view,並排放置在屏幕頂部,一個設置爲藍色,一個設置爲粉色。
咱們選擇iPhone5s模擬器設備並編譯運行應用,能夠看到一藍一粉這兩個方塊按照咱們設定的那樣杵在豎屏方向的屏幕上,沒有問題。當咱們把設備調整爲橫屏時,這兩個方塊像擁護黨同樣擁護着他們的座標位置,因此在橫屏的時候看着就不是那麼完美:
咱們再將模擬器改成iPhone6,而後編譯運行,此時在豎屏的時候就已經感受沒法再愛了。這兩個方塊並無按照咱們設置或設想的那樣在屏幕頂部中間,而是偏向了左邊,在右邊有一塊留白區域。
這是就是沒有佈局約束而致使的,藍色粉色方塊的大小、座標位置都是固定的,都是在4寸屏幕的參照下設置的,不論在哪一種尺寸的屏幕下,它們都在固定的那個座標位置和固定的大小,因此就會出現上面的狀況。
那麼接下來讓咱們給這兩個方塊添加一些佈局約束,再看看會有什麼神奇的事情發生。
頁邊間距約束(Leading and Trailing space)
頁邊間距約束分前部間距約束(Leading space constaint)和尾部間距約束(Trailing space constaint)。從屏幕上說就是左邊距和右邊距。咱們給藍色方塊添加左邊距約束,其值設置爲10,給粉色方塊設置右邊距約束,其值也設置爲10。
咱們再次在iPhone5s模擬器中運行應用,當橫屏時藍色方塊被左邊距約束拉到了屏幕左邊,粉色方塊被右邊距約束拉到了屏幕右邊。
水平間距約束(Horizontal space constaint)
給藍色方塊和粉色方塊添加水平間距約束,其值設置爲10。這個約束會使這兩個方塊之間的距離永遠約束爲10。
咱們再來運行應用,如今橫屏時兩個方塊之間的間距、它們與屏幕邊緣的間距都和豎屏時顯示的同樣了。可是其中粉色方塊爲了知足水平間距約束自行增長了方塊的寬度,變成了長方形。簡直是一隻老鼠壞了一鍋湯有木有。
從上面這個效果咱們能夠得知,除非咱們特別限制了view的尺寸,不然的話iOS會爲知足佈局約束而改變view的尺寸,也就是保持一個天然的尺寸。
等寬約束(Equal widths constaint)
咱們給這兩個方塊添加一個等寬約束來改善上面的狀況。
再次運行應用,如今在橫屏時因爲等寬約束的做用,兩個方塊的寬度保持了一致。咱們已經很是接近完美了。
方向比例約束(Aspect ratio constaint)
從上面的運行狀況來看各個約束都工做正常,但惟一不足的是原本在豎屏是兩個正方形方塊,在橫屏時缺變成了長方形方塊,由範爺變成了鳳姐這是人類沒法接受的。
咱們給這兩個方塊添加方向比例約束來解決這個問題。這個約束使方塊在知足其餘約束的前提下始終保持高和寬的比例相同。因此在橫屏時就會以方塊的寬度爲比例標準,將高度的比例改成寬度的比例。
用iPhone5s模擬器編譯運行應用,如今在橫屏狀態下兩個正方形方塊完美的呈如今咱們眼前。
咱們在iPhone6模擬器上再編譯運行應用,從下面的圖中咱們能夠很清晰的看到添加約束以前和以後的變化。佈局約束根據多出的空間大小將方塊放大到合適的尺寸以知足約束。
實踐佈局約束
到目前爲止,大家已經看到佈局約束神奇的做用和效果。是時候讓大家在大家本身的storyboard文件中添加布局約束了。
熟練佈局約束最好的方法就是多練習,從添加少許的佈局約束開始,一步步達到本身想要的效果。
另外有一點,我始終不認爲添加過多的佈局約束會對應用的性能產生影響。可是咱們也不能濫用約束佈局,好鋼要用在刀刃上,咱們儘量用最節儉的約束佈局達到咱們想要的效果。
添加布局約束的方式
這裏向你們介紹三種在storyboard中添加約束的方式:
1.底部佈局約束按鈕
這種方式多是最簡單直觀的一種方式,在屏幕上選擇一個或多個對象,而後點擊底部的佈局約束按鈕添加一個或多個須要的約束。它的好處是能夠直觀的看到當前選擇的對象已經添加了該類中的那些約束。
若是你指選擇了一個對象想要添加某個約束,但發現該約束是不可選的,那麼就意味着這個約束是適用於兩個以上對象的約束。
2.按住Control鍵拖拽鼠標
你也能夠選擇一個對象,而後按住Control鍵和鼠標左鍵,拖拽鼠標到另外一個對象(容器對象,也就是父對象或者選中對象本身),鬆開鼠標後會彈出適用的約束菜單,你能夠選擇約束進行添加。
這是我偏心的一種方式,由於它比上面那種方式來的快多了。
3.菜單/綁定快捷鍵
你也能夠經過菜單選項editor —> pin給一個或多個對象添加布局約束。這是效率最低的一種方式。若是你發現有些約束你會一遍遍的反覆添加,那麼你就能夠給該約束綁定一個快捷鍵來提升效率。
檢查和編輯已添加的佈局約束
檢查約束最簡單的方式就是選中一個對象,而後打開右側工具欄,選擇Size Inspector面板。或者在storyboard界面左側的結構樹中查看約束。
經過這兩種方式,你均可以選擇某個約束,而後編輯它。
移除佈局約束
佈局約束能夠添加天然也就能夠刪除。選中某個約束使其高亮顯示,而後按下Delete鍵移除該約束。
若是想移除某個對象上全部的約束,有一個快捷的方式。選擇該對象,而後在底部點擊Resolve Auto Layout Issues按鈕,選擇Clear Constaints。
佈局出現的問題和衝突
咱們在添加約束時,常常伴隨有警告或者錯誤出現。雖然有些警告是由於咱們尚未添加完約束出現的,當咱們添加完咱們設想的約束後警告就會天然消失。但大多數的警告仍是指明咱們的約束確實存在問題,須要咱們修復。
查看警告或錯誤最方便的方式就是在storyboard左側的結構樹中,在view controller的右邊會出現一個紅色或黃色的小圖標,向咱們指明這裏存在問題:
錯誤擺放view的警告
view位置的錯誤擺放是一個很常見的警告。當一個view沒有擺放在約束規定的位置的時候,會出現該警告。
這些問題會在你切換不一樣設備的模擬器或鼠標不當心移動了某個對象時出現。
選中一個錯誤擺放的對象,在屏幕上會出現佈局約束給你提示的正確的擺放位置。
點擊左側出現的黃色警告圖片,會彈出一個菜單,你能夠選擇讓Xcode改變約束,以適應當前該對象的位置,但一般狀況下咱們都選擇讓Xcode將該對象移動到約束規定的位置。
缺乏佈局約束的錯誤
咱們回到早些時候的示例中。這時候咱們沒有給方塊添加Y座標位置的約束。在運行時沒有問題,由於iOS會假設方塊的位置就是咱們在storyboard中擺放的那個位置。可是Xcode會提示咱們一個缺失約束的錯誤,爲了不意外發生(更換設備尺寸),我仍是要根據Xcode的提示添加缺失的約束。
咱們給這兩個方塊添加一個top space to to layout guide約束使方塊的位置更加清晰,並消除Xcode的錯誤提示。
Size Classes
自適應佈局的佈局約束天然是好東西,但也不是萬能的,有時候咱們也須要使用最基本的佈局,因此使用size classes將它們二者結合起來才能碰撞出更有激情的火花。
Size Classes並不表明真正的尺寸,而是咱們從感官上感受尺寸的種類,經過這種種類的組合,表示出不一樣屏幕尺寸設備的橫屏及豎屏。
咱們在給storyboard中的對象添加約束時能夠選擇給某一個size class添加約束,因此在你選擇特定的size class時,只能看到你添加的只適用於該size class的約束。
這些特性能使咱們有效的在不一樣的設備和屏幕方向中定義、設計不一樣的用戶界面。
Size Classes中的高和寬
Size Classes爲高和寬分別提供了三種類型:緊湊型(compact)、普通型(regular)、任意型(any)。用這三種高和寬的類型就能夠組合出9種size class,來表示不一樣的設備屏幕。
在實際運用中,咱們發現並非全部的尺寸都能在Size Classes中找到明確的組合(好比沒有組合能夠明確表示iPhone6 Plus的豎屏,iPad的橫豎屏也很差區分),可是咱們可使用表示這個尺寸範圍的組合。好比咱們能夠用Compact Width | Regular Height來表示iPhone6 Plus的豎屏。
接下來仍是用一個活生生的示例來向你們介紹Size Classes。
咱們的目標
這個示例是實現Instagram的一個詳細信息頁面,並讓它自適應更大的屏幕尺寸,在豎屏和橫屏中都展示出最合適的佈局。
咱們的目標是讓佈局自適應iPhone6的屏幕(這裏須要注意一下,我所說的自適應是指圖片、文字信息的佈局排版,對於我的信息的頭像不會根據佈局的變化而變化),在豎屏中各個信息按照堆棧方式從上到下佈局,在橫屏時各元素按照大小進行有序排列,而再也不是堆棧的方式:
給通用的size class添加約束
在這個示例中,咱們不會像上個示例那樣使用模擬器的實際尺寸來設計佈局,咱們使用Size Classes提供的抽象的屏幕尺寸,這裏咱們先使用通用的尺寸來設計佈局,也就是w Any | h Any尺寸。咱們要注意的是,在這個尺寸下添加的view或者約束必須是一些公用的,也就是說在任何尺寸,任何屏幕方向的狀況下都適用的。
這些約束包括:
除了以前介紹過的頁邊間距約束、水平間距約束、等高等寬約束、方向比例約束外還有頂部、底部間距約束。
添加完上述的view和約束後,storyboard裏應該是這番景象:
這裏要注意一下,目前這個界面的佈局還有不少關鍵點須要考慮橫屏和豎屏的佈局,可是這些工做不會在w Any | h Any尺寸下進行。大夥接着往下看。
爲iPhone的豎屏添加布局約束
如今在Size Classes選擇器中選擇w Compact | h Regular尺寸,這個size class適用於全部iPhone設備的豎屏界面,不論尺寸是多少。
當你在Size Classes選擇器中選擇某一個size class後,storyboard 中的view controller會實時的反映出你改變後的尺寸大小。
如今你就能夠爲iPhone的豎屏狀態從新設計view的位置和添加新的佈局約束了。下圖中說明了我在豎屏狀態下添加的約束:
個人storyboard中看起來是這樣的:
在這個階段,你能夠在3.五、四、4.七、5.5這幾個尺寸的模擬器中編譯運行應用,在豎屏狀態下看看它們的運行狀況,儘管在橫屏狀態表現的還很糟糕。
這裏要注意的是咱們並無定義圖片的寬度,咱們只是給圖片添加了相對父容器的左右邊間距,並將其值設爲了0。因此當屏幕尺寸增大的時候圖片的寬度在佈局約束的做用下也會增長,這時又由於咱們給圖片添加了高寬比例約束,因此圖片的高度也會隨之增長。
爲iPhone的橫屏添加布局約束
打開Size Classes選擇器,選擇w Any | h Compact,這個size class適用於任何一個尺寸的橫屏狀態。咱們將在這個size class下設計咱們但願在iPhone橫屏時顯示的用戶界面。
此時圖片的頂部、左側、底部都添加了相對於父容器的邊界約束。在顯示評論的label上添加了右側邊界約束。
當設備橫屏時,圖片在佈局約束的做用下移到了左側,我的信息label和評論label在約束的做用下被擠到了右側,而且評論label的高度增長,寬度減小。
如今來看看個人storyboard中顯示的內容。你們注意左側的對象結構樹中有不少個約束,可是有些是灰色的。那是由於這些灰色的約束在當前的size class下是禁用的,或者說不適用、不起做用。那些是豎屏時用到的約束。
如今在storyboard中切換size class時佈局也會隨之變化,更新很是及時和平滑。
咱們在模擬器中編譯運行應用,切換橫豎屏,能夠看到佈局切換的效果,過分很是天然平滑。
爲了能讓你們看清楚佈局變化過分的細節,我放慢了這個git動畫。你們注意,在佈局變化時屏幕上的組件有一個層級關係,從該示例中咱們能夠看到圖片view的層級高於我的信息label和評論label。因此咱們在設計佈局的時候就要考慮如何給view分層,包括在普通佈局中不會被覆蓋的view。這是一個細節問題。
屏幕預覽助手編輯器
Xcode6中另外一個值得關注的功能是屏幕預覽助手。它能夠避免你一遍遍的在不一樣屏幕尺寸的模擬器中編譯運行應用來檢查佈局的正確與否。你能夠在屏幕預覽編輯器中添加一個或多個你想查看的屏幕尺寸,並可讓他們呈現橫屏或豎屏的狀態。
固然它也不是很是完美(由於在預覽時導航欄的顏色會丟失),可是切換Double Length Pseudolanguage選項很方便,便於你檢查問題。
從上圖中你們能夠看到我在屏幕預覽編輯器中顯示了3.5寸屏幕的橫屏和4寸屏幕的豎屏,總體佈局沒有問題,可是當選擇Double Length Pseudolanguage使label中的文字都增長一倍時,問題就出現了,我的信息和評論的label長度沒有自適應。
爲iPad佈局添加約束
如今咱們將Sizae Classes調整爲w Regular | h Regular,這個size class表示了iPad的橫屏和豎屏大小。
和往常同樣,咱們先調整圖片和各個label的位置及大小,調整滿意後,再添加相關的約束。在iPad佈局中我打算將圖片的尺寸設置爲固定尺寸(不像iPhone中那樣隨着橫屏和豎屏改變圖片的尺寸),並將我的信息和評論label緊跟在圖片下面。
個人storyboard如今看起來是這樣的:
以往,咱們都是在特定的size class中添加相關的約束,但在iPad佈局中,咱們不只僅只添加一些約束。
由於在iPad佈局中有很大的空餘空間,因此咱們不僅是從新排列一下組件的位置和大小,咱們還要添加一些其餘的組件。在這個示例中,咱們再添加兩個圖片view(分別表示當前顯示圖片的上一張圖片和下一張圖片)。
再來看看個人storyboard:
咱們不須要對這兩個圖片手動的設置高寬,而是給它們設置對於主顯示圖片的相對高寬便可。
這樣作的好處是當主顯示圖片的尺寸更改時,咱們不須要本身手動計算和更改這兩個圖片的尺寸,相對高寬會自動針對主顯示圖片的尺寸調整這兩個圖片的尺寸。
我沒有製做在iPad上運行的gif動畫,但這裏有iPad橫屏豎屏的運行圖片,你們能夠看看:
使用佈局視圖和間距視圖
目前Xcode提供的佈局約束能夠知足大部分的佈局需求,可是有些場景下須要變通的使用約束才能達到咱們想要的效果。
佈局視圖示例
經過Xcode提供的約束,咱們能夠很容易設置組件與view controller view的邊緣的間距,也能夠很容易的讓組件在view controller view中水平居中顯示和垂直居中顯示。可是卻不太容易設置組件與view controller view的水平中線或垂直中線的間距。像這樣:
下面向你們介紹兩種實現該需求的方法。首先咱們先添加一個view,背景色設置爲透明,讓它在屏幕中垂直居中顯示,它做爲該需求中組件的父容器,由於父容器在屏幕中是垂直居中的,因此能夠給組件添加相對於父容器的Center X約束,就能夠達到咱們的需求了:
可是經過上述的方式未免會使咱們的佈局的層級關係太過複雜,我更但願佈局比較扁平一些,不須要太多的層級關係。由於上述方法中的容器view主要是用於佈局使用,因此這種view我稱之爲佈局視圖。
咱們來改進一下方法,首先也是在view controller view中添加一個佈局視圖,我習慣將高度設置爲20(這個值隨我的喜愛或實際狀況而定),而後將它和屏幕的頂部、左側、右側的間距設爲0,這樣的話這個佈局視圖就和狀態欄重合了,咱們將這個佈局視圖設置一個深一點的顏色,而後將它的hidden屬性設置爲true,這樣佈局視圖的顏色就會變淺,也不太會影響咱們的佈局,並且在應用運行時是不會顯示該視圖的。如今咱們的組件就能夠設置相對於佈局視圖的Center X約束來實現咱們的需求了。
間隔視圖示例
以前咱們學習瞭如何使用約束設置視圖和視圖邊緣的間距,而且當屏幕尺寸增長時視圖也會相應的改變大小,但它們的間距不會改變。
可是若是咱們但願當屏幕增長尺寸時,視圖的大小保持不變,只是增長間距呢?
從理論上講,實現該需求可能可使用相似等寬這樣的約束,可是現實每每的是骨幹感的。
這時咱們就須要間距視圖出場了,和佈局視圖同樣,間距視圖能夠設置一個深一點的顏色,hidden屬性要設置爲true。
咱們在每一個視圖與視圖間距之間添加一個間距視圖,設置每一個視圖與相鄰間距視圖的邊緣間距約束,而後給全部的間距視圖添加相對於view controller view的等寬約束,設置合適的比例便可。