ios自適應佈局

轉自:http://www.cocoachina.com/ios/20141020/9978.html

Apple從iOS 6加入了Auto Layout後開始就比較委婉的開始鼓勵、建議開發者使用自適應佈局,但是到目前爲止,我感覺大多數開發者一直在迴避這個問題,不管是不是由於歷史原因造成的,至少他們在心底還堅守着固定佈局的老傳統思想。

隨着iPhone6、iPhone6 Plus的到來,使用自適應佈局更是迫在眉睫的事,固定佈局的老傳統思想脆弱的不堪一擊。現在的iPhone有4種尺寸,如果算上iPad,現在Apple的iOS設備有5種尺寸。我們在準備使用自適應佈局設計應用界面之前,可以把這5種尺寸劃分爲3種分辨率和屏幕方向,這樣在設計時分類會更加清晰一些。

我們先來看一張自適應佈局的效果圖:

當你們學習完這篇文章後,你們應該會比較自如的使用 storyboard、constaints、size classes 這三個Apple在Xcode裏提供的工具,去探索和構建巧妙的自適應佈局。

Storyboards

在Xcode中,storyboard是一個可以讓我們對應用界面進行可視化佈局的工具,你首先可以在storyboard文件中看到一個或若干個iOS設備屏幕大小的佈局區,然後你可以從組件庫(Object Library)中拖拽組件到屏幕布局區中進行佈局(比如按鈕、圖片、文本框、labels等),你還可以定義屏幕布局區之間的連接關係。

用Xcode的術語來說,人們可以看到、觸碰到或以其他方式(按鈕、圖片、文本框、labels等)進行交互的用戶界面被稱爲views。屏幕中包含和管理這些views的容器稱爲view controller。

當我們在storyboard中添加一個view controller後,我們所看到的並不是一個我們熟知的屏幕尺寸,而是一個600X600的正方形:

從上圖我們可以很明顯的看出,storyboard中顯示的屏幕尺寸不是實際設備的尺寸。Apple這樣做的目的是將屏幕尺寸進行了抽象化,也就是說你可以將這個正方形的屏幕看成iphone4的屏幕,也可以將它看成iphone6的屏幕。

模擬器的尺寸

當你習慣了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.5、4、4.7、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的等寬約束,設置合適的比例即可。

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