智能手機發展到今天,屏幕尺寸變的愈來愈多,iPhone從最初的3.5寸屏幕,到後來推出的4寸屏,直到蘋果推出iPhone 6 和 iPhone 6Plus,也宣告着蘋果陣營被完全攻破,進入了屏幕尺寸碎片化的時代。只爲某一個屏幕尺寸設計的日子已經不在存在。爲了適配全部的屏幕,設計師必須考慮各類屏幕尺寸。可是又不可能爲每一個尺寸都設計一遍。那麼咱們又該如何面對屏幕碎片化的困境?html
圖1,圖片來自:HTTP://WWW.PAINTCODEAPP.COM/NEWS/ULTIMATE-GUIDE-TO-IPHONE-RESOLUTIONSios
蘋果給出的答案是AutoLayout。讓你能用一個設計來適配全部屏幕,理論上講從iPhone4適配到iPad pro均可以。它但願你忘記某個具體的尺寸。實際上你能夠隨意拖出一個任意尺寸的畫布進行設計,標註好後就能夠交給工程師開發。app
首先咱們先看一下,蘋果的開發軟件Xcode上是讓你怎麼進行頁面佈局的。佈局
圖2,XCODE.STORYBOARDspa
中間那塊白色的正方形就是畫布,若是你是使用storyboard佈局的話(iOS的佈局方式有不少種,storyboard只是其中一種,我在後面會講),你能夠將你設計好的控件放到這個畫布上去,根據你標註的尺寸定義好它們的位置關係,接下來AutoLayout就會自動適配各個屏幕了。聽上去好像很神奇。設計
有些人會有疑問:我是以iPhone6的尺寸爲基礎進行設計和標註的,怎麼可能在一個正方形上根據我標註的尺寸定好它們的位置關係,放到這個正方形上,個人標註不是全亂了嗎?答案是,是,也是否是。若是你在設計和標註時只爲iPhone6設計,把適配的問題都拋給了工程師,頗有可能最後出來的結果不是你想要的。相反,即便你是在iPhone6上進行設計,可是你並無把思惟侷限在某個尺寸上,那麼你的標註放在正方形上也不會亂。code
確切的講,若是你是以約束爲基礎(constraint-based)來設計的界面,那麼不管屏幕怎麼變化,你的設計也會跟着進行調整。htm
下面我就來說講AutoLayout究竟是如何工做的,以及該如何用約束的思想來進行設計。blog
對於iOS開發來說,一般會使用的是兩種佈局方式。一種是使用代碼設置每一個視圖(View)的Frame來進行定位。另外一個則是使用AutoLayout進行佈局(能夠在storyboard上,也可使用代碼)。假設咱們在iPhone6(375*667)的尺寸下放了有兩個視圖,A和B。圖片
Tips:在iOS開發中使用的單位是point,也就是@1x下的尺寸。若是你是以iPhone6(750*1334Px)的尺寸進行設計的,那麼裏面的尺寸都要除以2才能用。因此建議你們在@1x的環境下設計。本文不作特殊說明,沒標單位的標註,默認單位都爲point。
1.Frame定位
設置Frame進行定位的方法不是本文討論的重點,我只在這裏簡單介紹一下。首先在iOS裏的座標系和咱們平時用的有點不一樣。它的座標原點在左上角。每一個視圖都有本身獨立的座標系。見下圖。
圖3,使用FRAME進行定位
一般咱們定義一個Frame的代碼(Swift)是這樣的:
1
|
let frame = CGRectMake(x:CGFloat, y:CGFloat, width:CGFloat, height:CGFloat)
|
固然你不須要看懂它,只須要知道它要你提供四個參數:x,y,width,height。x ,y 是你要定位的視圖的原點相對於包含它的視圖的(superView)座標系的座標。width,height 固然就是你要定位的視圖的寬度和高度了。
總結一下就是你須要提供位置信息(location)以及尺寸(size)信息。
因此上圖中A,和 B的Frame應該是這樣的:
1
2
|
let frameA = CGRectMake(60, 60, 255, 160)
let frameB = CGRectMake(60, 280, 255, 160)
|
2.AutoLayout定位
AutoLayout佈局背後的邏輯則徹底不一樣於上一種方式。同一個圖,AutoLayout能夠用下圖這種方式來表示。
圖4,AUTOLAYOUT佈局
AutoLayout是一般是經過定義一系列的約束(constrains)來進行定位的。和Frame定位同樣,它一樣須要你提供位置和尺寸信息,可是和Frame不一樣的是,它不是讓你直接提供x,y,width,height,而是經過你給的約束來推斷出相應的尺寸和位置。只有當能從你給的約束關係中推斷出位置和大小信息,並且尚未衝突時,才能經過。
如上圖中的視圖A,咱們經過上下左右四個約束定好了它的位置。咱們提供了它的高度,可是咱們並無給出它的寬度。以前說過,要肯定一個視圖的佈局,你須要提供位置以及尺寸信息。而這裏咱們卻沒有提供寬度。應爲寬度不是一個固定的數值,須要AutoLayout本身經過現有的約束來推斷出視圖A的寬度 = 375(屏幕寬度)— 60—60 = 255,這樣當屏幕寬度變化時,視圖A的寬度也會隨之變化。
AutoLayout可以根據你在相應視圖上設置的約束,自動計算出的你定義的視圖的位置和大小。
圖5,當外部環境(屏幕寬度)變化時
當週邊環境變化時,它也隨之改變,這就是AutoLayout能適配不一樣屏幕的祕訣。
AutoLayout的應用並不侷限於應對外部環境的變化(屏幕大小變化),即便在同一個屏幕內,當頁面內容開始變化時,AutoLayout也能作出相應的調整。假設如今由於某種緣由,視圖A的高度變爲了210。那麼就會出現如下兩種結果:
圖6左,FRAME
圖6右,AUTOLAYOUT
用Frame定位方式,由於視圖A,B的位置信息是獨立的,A的變化,並不會影響B的位置,因此當A變高時,A,B之間高度方向的距離就被壓縮了,能夠想象,當A繼續變高時,A和B之間就會出現疊加的狀況,這顯然不是咱們但願看到的效果。
而AutoLayout則不一樣,因爲B高度方向的位置是相對於A的,因此當A變高時,B的位置也會跟着變化。這固然是咱們但願看到的結果。
因而可知,AutoLayout的應用場景不侷限於適配不一樣的屏幕尺寸,即便在軟件運行的過程當中,當頁面變化時它也可以跟着調整。
須要提一下的是,使用Frame定位的方式也是能實現上面這種AutoLayout的效果的,反之咱們也能使用AutoLayout來實現像Frame這種A,B不相互影響效果,我在這裏不細說,有興趣的能夠本身去思考一下。舉這個例子,只是爲了說明絕對定位和相對定位的區別。
3.AutoLayout 的屬性(AutoLayout Attributes)
相對於Frame一般要你提供的x,y,width,height,AutoLayout可用的屬性則多的多,經常使用的屬性有這些:
Left
Right
Top
Bottom
Leading
Trailing
Width
Height
CenterX
CenterY
Baseline
查看全部屬性可點擊這裏:NSLayoutConstraint
圖7,AUTOLAYOUT 屬性
這些屬性也大概能夠分爲兩類:大小(size)如width ,height ;位置(Location)如Leading,Trailing,Top,Button。
有了這些屬性,咱們不只可以定義不一樣視圖之間的距離,讓它們對齊,定義不一樣視圖之間的相對尺寸,甚至能夠定義一個視圖的長寬比。
值得注意的是其中的Leading 和Trailing,並不等於Left和Right。Leading表明的是閱讀開始位置。一般咱們都是習慣從左邊到右來閱讀,這種狀況下Leading就是Left,Trailing就是Right。但並非全部的國家都是依照這個方式的,好比中國古代的書,就是從右到左的,這時候Leading就在Right了。若是你的App用戶是國際化的,須要注意這個問題。一般狀況下,咱們都使用Leading,Trailiing。
圖8,不一樣語言環境下LEADING和TRAILING的區別
圖9
假設咱們有以上兩個View,如今要求他們間隔距離爲8,如上圖所示。那麼他們之間的約束關係就能夠這麼表示:
1
|
ViewB.Leading = 1.0 x ViewA.Trailing + 8
|
其中1.0 是一個係數(Multiplier),這種狀況下,這個係數爲1.0
4.舉個例子
下面就講一個具體的例子來講明一下AutoLayout應用。
假設我設計了一個這樣的界面(375*667),接下來要交給工程師進行開發。個人要求以下:
1.三個視圖離頁面兩邊的距離都爲37.5
2.每一個視圖之間的距離,包括視圖離頁面頂端和底端的距離都要同樣,爲40
3.三個視圖的寬度和高度要同樣。
我按照這些要求進行了標註,如下就是我想達到的效果以及個人標註:
圖10左,我要實現的效果
圖10右,個人標註
先分析一下咱們的標註。
首先我要求每一個視圖離頁面兩邊的距離都爲37.5。在標註裏我很明確地說明了這個問題。
其次,我要求每一個視圖之間的距離,包括視圖離頁面頂端和底端的距離都要同樣,爲40。在標註中我也很明確地說明了這一點。
最後,我要求每一個視圖的寬度和高度要同樣。在標註裏,每一個視圖的高度都標了169,符合我同樣高度的要求。我給第一個視圖標上了寬度300,其餘兩個和第一個首尾對齊,也是300,符合我同樣寬度的要求。
乍一看這個標註沒有問題。可是這裏咱們確忽略了一個很重要的問題。這個圖我是以iPhone6的尺寸來設計的,可是實際狀況,它並不僅會出如今iPhone6的屏幕上。按照上面的標註,標註的總寬度 = 37.5*2 + 300 = iPhone6的屏幕寬度(375)。可是若是換一個手機屏幕,這個等式就不成立了。一樣,高度也是這個問題。這樣就和實際狀況產生了衝突。
Tips:當你的標註在寬度方向,或高度方向的數值加起來等於某一個具體的屏幕尺寸時,你就須要去從新去檢查你的標註了,須要說明那些尺寸是固定的,哪些尺寸是可變的。
顯然,工程師沒法知足你標註的全部尺寸要求。若是他只看到你給的標註文件,而不知道你的三點要求。那麼這個標註在寬度方向大概就出現瞭如下幾種可能性:
1.保持兩邊各37.5的邊距(margin)要求,每一個視圖的寬度根據屏幕的寬度來伸縮
2.每一個視圖的寬度保持300不變,兩邊的邊距根據屏幕的寬度來伸縮
3.視圖的寬度和邊距隨着屏幕的寬度變化一塊兒縮放
從咱們以前的要求來看,咱們但願的是第一種可能性的,只是咱們的標註沒有很好的說明這個點。工程師須要靠本身的理解來選擇其中一種,有時候他的選擇可能並非咱們想要的結果。
咱們該如何標註,來很好的表達個人要求?正確的標註應該是這樣的:
圖11,正確的標註方式
首先,我去掉了寬度的標註,就像上個例子說的同樣,咱們須要AutoLayout本身來計算出它的寬度,也就意味着咱們是但願每一個視圖的寬度隨着屏幕的寬度變化而變化。其次,我去掉高度的具體數值,只標了一個h。一樣,由於屏幕的高度是不固定的,因此我沒法給出具體的高度,可是我又要求每一個視圖的高度是同樣的。經過給每一個視圖標註高度h,來表示他們的高度同樣。
5.表達三種不一樣可能性
以前我說過,我第一次給出的標註大概能夠有三種不一樣的理解,那麼咱們又該如何來表達這三種可能性呢?下面我就來講一下,如何使用AutoLayout的方式標註,來很明確地來表現以上三種可能性。
圖12
第一個視圖的標註,保持兩邊各37.5的邊距(margin)要求,每一個視圖的寬度根據屏幕的寬度來伸縮,這個上面說過。
第二個,我標註了寬度,沒標邊距。可是咱們要求它水平方向居中,經過這個約束來肯定它水平方向的位置。這樣邊距就能夠根據屏幕的寬度變化而變化。
第三個,我標註了寬度爲80%的屏幕寬度,這樣它就能作到和屏幕一塊兒縮放。
圖13
我在Xcode上添加好了上面要求的約束,並選擇在不一樣的模擬器上運行。這樣就能夠看到咱們設計的頁面在不一樣設備上運行的效果了。如下就是它在不一樣屏幕尺寸下顯示的效果:
圖14
能夠看到,在iPhone6上如出一轍的三個視圖,應爲咱們設置了不一樣的約束,在不一樣的設備上運行就出現了不同的效果。由於AutoLayout是根據你設置的約束,自動計算出的你定義的視圖的位置和大小。
爲了適配更多的屏幕,咱們在設計的時候須要用相對定位的思惟來佈局。