设计之家 > 靈感 > 網頁UI > 網頁理論 >

一稿適配所有iOS設備——AutoLayout入門

作者:董 浩龍 來源:點融設計中心DDC 時間:2016-07-13

智能手機發展到今天,屏幕尺寸變的越來越多,iPhone從最初的3.5寸屏幕,到後來推出的4寸屏,直到蘋果推出iPhone 6 和 iPhone 6Plus,也宣告著蘋果陣營被徹底攻破,進入了屏幕尺寸碎片化的時代。隻為某一個屏幕尺寸設計的日子已經不在存在。為了適配所有的屏幕,設計師必須考慮各種屏幕尺寸。但是又不可能為每個尺寸都設計一遍。那麼我們又該如何面對屏幕碎片化的困境?

 圖1,圖片來自:HTTP://WWW.PAINTCODEAPP.COM/NEWS/ULTIMATE-GUIDE-TO-IPHONE-RESOLUTIONS

蘋果給出的答案是AutoLayout。讓你能用一個設計來適配所有屏幕,理論上講從iPhone4適配到iPad pro都可以。它希望你忘記某個具體的尺寸。實際上你可以隨意拖出一個任意尺寸的畫布進行設計,標注好後就可以交給工程師開發。

首先我們先看一下,蘋果的開發軟件Xcode上是讓你怎麼進行頁面布局的。

圖2,XCODE.STORYBOARD

中間那塊白色的正方形就是畫布,如果你是使用storyboard布局的話(iOS的布局方式有很多種,storyboard隻是其中一種,我在後面會講),你可以將你設計好的控件放到這個畫布上去,根據你標注的尺寸定義好它們的位置關系,接下來AutoLayout就會自動適配各個屏幕了。聽上去好像很神奇。

有些人會有疑問:我是以iPhone6的尺寸為基礎進行設計和標注的,怎麼可能在一個正方形上根據我標注的尺寸定好它們的位置關系,放到這個正方形上,我的標注不是全亂了嗎?答案是,是,也是不是。如果你在設計和標注時隻為iPhone6設計,把適配的問題都拋給了工程師,很有可能最後出來的結果不是你想要的。相反,即使你是在iPhone6上進行設計,但是你並沒有把思維局限在某個尺寸上,那麼你的標注放在正方形上也不會亂。

確切的講,如果你是以約束為基礎(constraint-based)來設計的界面,那麼無論屏幕怎麼變化,你的設計也會跟著進行調整。

下面我就來講講AutoLayout到底是如何工作的,以及該如何用約束的思想來進行設計。

對於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)是這樣的:

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應該是這樣的:

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

查看所有屬性可點擊這裏:

https://developer.apple.com/library/ios/documentation/AppKit/Reference/NSLayoutConstraint_Class/index.html#//apple_ref/c/tdef/NSLayoutAttribute 

圖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的區別

圖8,不同語言環境下LEADING和TRAILING的區別

圖9

假設我們有以上兩個View,現在要求他們間隔距離為8,如上圖所示。那麼他們之間的約束關系就可以這麼表示:

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是根據你設置的約束,自動計算出的你定義的視圖的位置和大小。

為了適配更多的屏幕,我們在設計的時候需要用相對定位的思維來布局。

這次就講到這裏,下一篇我會介紹更多AutoLayout相關知識,以及如何使用Xcode來添加約束,做出你自己設計的頁面。

Via: DDC

标签:iOS

推薦設計

最新文章