第 5 章
Auto Layout 介紹

Life is short. Build stuff that matters. – Siqi Chen

建立一個 Hello World App 是不是很有趣呢?在建立一個真實 App 之前,我們在本章中先討論一下 Auto Layout。

Auto Layout 是一個以約束條件為基礎的佈局系統(constraint-based layout system ), 它讓開發者能夠開發一個能自適應 UI,可以依照螢幕的尺寸以及裝置的方向來調整。有些初學者會覺得這個部分很難,而儘量避免去使用它,但是請相信我,當你習慣之後, Auto Layout 會成為你之後無比仰賴、非常重要的 App 開發工具。

自從 iPhone 在十年前釋出之後,只有一種螢幕尺寸:3.5 英吋。然後出現 4 英吋的 iPhone 。在 2014年,Apple導入了 iPhone 6 以及 6 Plus,現在 iPhone 有了不同的螢幕尺寸, 包含 3.5 英吋、4 英吋、4.7 英吋、 5.5 英吋與 5.8 英吋顯示器。當你想設計你的 App UI,你必須要應付不同的螢幕尺寸。如果你的 App 準備支援 iPhone 與 iPad(也就是所謂了通用(universal)App,你需要確保這個 App能夠相容其他的螢幕尺寸,其中包含 7.9 英吋、9.7英吋、10.5 英吋與 12.9 英吋。

如果沒有使用 Auto Layout,想要建立一個支援各種螢幕解析度的 App 將會非常困難。這也是為什麼我想要在本書一開始的內容,先教你學會 Auto Layout,而不是直接寫 App 程式碼的原因。這會花費你一些時間,不過我想要你能夠了解其中觀念,在本章以及接下來的章節中,我會協助你建立設計「自適應使用者介面」(adaptive user interface )的紮實基礎。

Quick note: Auto Layout 並不如開發者所想像的困難。當你瞭解這些基礎,以及下一章會學習到的堆疊視圖,你將能夠使用 Auto Layout 來針對各種型式的 iOS 裝置建立出複雜的使用者介面。 

為什麼需要Auto Layout?

這裡舉個例子,或許你就會對我們為何要使用 Auto Layout 更有概念了。請打開第 3 章的 Hello World 專案,以 iPhone SE 與 iPhone 7/8 Plus 模擬器取代在 iPhone 7 模擬器中執行程式,其結果會如圖 5-1 所示,除了在 4.7 吋螢幕 之外,在其他的 iPhone 裝置中畫面的按鈕皆沒有置中。

圖 5-1. App 的 UI 在 iPhone SE(4 英吋)、iPhone 6(4.7 英吋)、iPhone 6 Plus(5.5 英吋)與 iPhone X Plus(5.8 英吋)看起來不太一樣
圖 5-1. App 的 UI 在 iPhone SE(4 英吋)、iPhone 6(4.7 英吋)、iPhone 6 Plus(5.5 英吋)與 iPhone X Plus(5.8 英吋)看起來不太一樣

我們來試試其他狀況。

點選「Stop」按鈕,並選擇 iPhone 7 模擬器來執行 App。啟動模擬器後,在選單上點選「Hardware → Rotate Left(或 Rotate Right)」,此時裝置便會轉為橫向(landscape) 模式。另外,你可以按下鍵 command 加上左右鍵,將裝置往側邊轉向。同樣的,「Hello World」按鈕的位置還是沒有置中。

為什麼會這樣呢?出了什麼問題嗎?

首先,你應該知道 iPhone 有不同的螢幕尺寸:

  • iPhone5/5s/SE 的螢幕大小在直立(portrait)模式的情況下,水平方向是 320 點(640像素),垂直方向為568 點(1136 像素)。
  • iPhone 6/6s/7 的螢幕大小在水平方向是 375 點(或750像素),垂直方向則是 667點(或1334 像素)。
  • iPhone 6/6s Plus/7 Plus 的螢幕大小在水平方向是 414 點(或1242像素),垂直方向則是 736 點(或2208 像素)。
  • 全新品牌 iPhone X 的螢幕大小在水平方向是 375 點(或1125 像素),垂直方向則是 812 點(或2436 像素)。
  • iPhone 4s 的螢幕大小則分別為 320點(640像素)以及 480點(960像素)。

為什麼是點(Points )而不是像素(Pixels )呢?

時間回到 2007 年,Apple 推出的最原始iPhone,3.5 英吋、320×480 像素的畫面解析度的顯示器, 即水平方向是 320 像素,垂直方向是 480 像素。Apple 把這個螢幕解析度繼續沿用到 iPhone 3G 與 iPhone 3GS。很明顯的,如果我們在那時候建造一個 App,一個點相對應一個像素。之後 Apple 推出了 iPhone 4 搭配視網膜(retina )顯示器。畫面的解析度變成兩倍到 640×960 像素。也就是一個點相對應二個像素。 這個點系統(point system )讓開發者輕鬆不少,不論螢幕解析度如何變化(例如:解析度再變兩倍至 1280×1920 像素),我們要面對的依然是點與最基本的解析度(也就是 iPhone 4/4s 是 320×480 像素, iPhone 5/5s/SE 是 320×568 像素),而這些點與像素間的轉換工作,則由 iOS 處理。

如果沒有使用 Auto Layout,我們在 Storyboard 所佈局的按鈕位置是固定的,換句話說,我們將按鈕框架的原點以程式固定,以我們的範例來說,「Hello World」按鈕的框架原本設在(147, 318),因此不論你是使用 4 英吋、4.7 英吋或者是 5.5 英吋模擬器,iOS 會將按鈕繪製在指定位置。圖 5-2 顯示了這個按鈕在不同裝置下的原始位置,這就說明了「Hello World」按鈕只能在 iPhone 7 裝置置中,在其他 iOS 裝置以及橫向模式中都會偏移的原因。

圖 5-2. 按鈕在 iPhone 7 Plus、 iPhone 7 與 iPhone SE 的呈現結果
圖 5-2. 按鈕在 iPhone 7 Plus、 iPhone 7 與 iPhone SE 的呈現結果

很顯然,我們希望 App 在所有 iPhone 機種,不管是在橫向模式或直立模式都要看起來一致才是。此即我們需要學習 Auto Layout 的緣故,也是針對我們剛才討論到畫面佈局問題的答案。

Auto Layout 與約束條件有關

如前所述,Auto Layout 是以約束條件(constraints )為基礎的佈局系統。它讓開發者建立自適應 UI,可以因應螢幕尺寸與方向的不同。嗯,聽起來好像不錯,但是什麼是「以約束條件為基礎的佈局」?

讓我以白話來表達好了,再次以「Hello World」按鈕為例, 如果你要把它擺在視圖的中間,你會如何描述它的位置呢?也許你會這樣描述:

不管螢幕解析度與方向為何,按鈕應該是在水平以及垂直方向的中間位置。

這邊就會得到兩個約束條件:

  • 水平置中。
  • 垂直置中。

這些約束條件顯示了按鈕在介面中的佈局。

Auto Layout 是和約束條件有關。雖然我們把約束條件以文字表達,但這些約束條件是以數學形式來呈現。舉例來說,當你要定義一個按鈕的位置,你可能會這樣說:「左側邊緣距離內容視圖的邊緣是30 點」,這會被轉換為`button.left = (container.left + 30)

很幸運地,我們不需要去和公式打交道,你只要知道如何描述這些約束條件並使用介面建構器來建立它們即可。

好了,Auto Layout 的理論就談到這裡為止。現在我們來了解如何在介面建構器中定義佈局約束條件,以讓「Hello World」按鈕置中。

在介面建構器中做即時檢視

首先, 打開 HelloWorld 專案的Main.storyboard( http://www.appcoda.com/resources/swift4/HelloWorld.zip)。在加入佈局約束條件至使用者介面之前,我們先介紹 Xcode 的一個很方便的功能。

你可以使用模擬器來測試 App UI 在不同尺寸螢幕的呈現狀況,不過,Xcode 在介面建構器中提供了一個設定欄(Configuration Bar ),讓使用者能夠即時檢視使用者介面。

介面建構器預設上是以 iPhone 8(4.7 英吋) 檢視 UI。想要看 App 在其他裝置的顯示狀況,點選 View as: iPhone 8 按鈕來打開設定欄,然後選取你想測試的 iPhone/iPad 裝置。你也可以改變裝置的方向來了解 App UI 的變化。圖5-3 顯示 Hello World App 在 iPhone 8 橫向模式的即時檢視(live preview )。

圖 5-3. 使用 Xcode 的設定欄做即時檢視
圖 5-3. 使用 Xcode 的設定欄做即時檢視

這個設定欄是自 Xcode 8 以來很棒的一個功能,請花點時間來熟悉一下。

Quick note: 你可能想知道這裡的「(wC hC)」的含義。現在可以先略過,將重點放在Auto Layout 的學習,之後的章節將會討論到它。

使用Auto Layout將按鈕置中

我們繼續討論 Auto Layout。Xcode 提供了兩種定義 Auto Layout 約束條件的方式:

  1. Auto Layout 選單
  2. control 加上拖曳

我們將在本章示範這兩種方法,首先從 Auto Layout 選單開始。在介面建構器的編輯器右下角處,你會找到 5 個按鈕。這些按鈕就是佈局選單,你可以使用它們來定義各種型態的佈局約束條件與解決佈局問題,如圖 5-4 所示。

圖 5-4. Auto layout 選單
圖 5-4. Auto layout 選單

每一個按鈕有它自己的功能:

  • Align – 建立對齊的約束條件,例如:對齊兩個視圖的左側。
  • Pin/Add New Constraints – 建立間距的約束條件,例如:訂出 UI control的寬度。
  • Resolve auto layout issues – 解決佈局問題。
  • Stack:視圖嵌入至堆疊視圖(stack view)。堆疊視圖自 Xcode 7 開始的新功能。我們在下一章會進一步討論它。
  • Update frames – 以設定的約束條件來更新框架的位置與尺寸。

如同之前所說明的,要將「Hello World」按鈕置中,你必須要定義兩個約束條件: Center HorizontallyCenter Vertically,這兩個約束條件都相對於該視圖。

要建立約束條件,我們將會使用 Align 按鈕。首先,選取在介面建構器的 Hello World 按鈕,然後在佈局選單中點選 Align 按鈕圖示。在彈出式選單中,勾選「Horizontal in container」與「Vertically in container」,接著點選「Add 2 Constraints」按鈕,如圖 5-5 所示。

圖 5-5. 使用 Align 按鈕來加入約束條件
圖 5-5. 使用 Align 按鈕來加入約束條件
Quick tip: 你可以按下 command+0 來隱藏專案導覽器,如此可以釋放更多的畫面空間,可有利於 App 設計。

此時你應該會見到一組藍色約束線。如果你在文件大綱(Document Outline )視圖展開 Constraints 選項,你會見到按鈕有兩個新的約束條件。這些約束條件可以確保按鈕總是保持在視圖中心。另外,你也可以在尺寸檢閱器(Size Inspector )中檢視這些約束條件,如圖 5-6 所示。

圖 5-6. 在文件大綱與尺寸檢閱器檢視約束條件
圖 5-6. 在文件大綱與尺寸檢閱器檢視約束條件
Quick note: 當你的視圖的佈局設定正確且沒有模糊不清的話,這些約束線是以藍色來呈現。 

好的,準備再一次測試 App,你可以點選「Run」按鈕,分別以iPhone 7/8 Plus(或者是 iPhone SE )來啟動 App。另外,只要使用設定欄選取另外的裝置或者變更裝置的方向,就可以確認佈局是否正確。現在,不管畫面大小與方向為何,按鈕都應該已經完美置中了。

解決佈局約束條件問題

剛剛我們所設定的佈局約束條件很完美,不過有時候並非都能如此順利,Xcode 可以聰明的偵測出任何約束條件的問題。

試著拖曳「Hello World」按鈕到畫面的左下方,Xcode 可以立刻偵測出一些佈局問題, 同時相對應的約束線會變成橘色,指出錯位的項目,如圖 5-7 所示。

圖 5-7. 介面建構器使用橘/紅線來指出 Auto Layout 問題
圖 5-7. 介面建構器使用橘/紅線來指出 Auto Layout 問題

當你所建立的約束條件有模糊或有所衝突時,便會出現自動佈局問題,這裡我們指定按鈕應該在容器(也就是視圖)中水平與垂直置中,不過,現在按鈕移到視圖的左下角,介面建構器發現了這邊有所模糊,因此它使用了橘色線來標示佈局問題,虛線的部分則表示這個按鈕應該存在的位置。

當有任何的佈局問題,文件大綱視圖會顯示出一個紅/橘色的揭露箭頭(disclosure arrow ),按下這個揭露箭頭,你會看見問題清單,如圖 5-8 所示。對於某些問題,介面建構器可以聰明地幫助我們解決佈局問題,點選問題旁邊的指示圖示,此時會出現幾個解決方案,以這個例子來說,選取「Update Frame」選項,然後點選「Fix Misplacement」按鈕。按鈕便會移到視圖的中心了。

圖 5-8. 解決錯位問題
圖 5-8. 解決錯位問題

另外,你也可以只點擊佈局欄上的「Update frames」按鈕來解決這個問題。

這個佈局問題是我自己動手移動所產生的。我只是想要示範如何發現佈局問題並修復它。當你跟著本書的範例來練習時,很有可能會面臨到類似的問題。此時你應該要知道如何輕易且快速的解決佈局問題。

預覽 Storyboard的其他方式

你已經知道如何使用設定欄來即時預覽你的 App UI,Xcode 提供一個另外的預覽功能來讓開發者同時在不同裝置預覽使用者介面。

在介面建構器,點選「Assistant 彈出式選單→ Preview(1)」,按住option鍵,然後點選「Main.storyboard(Preview)」。你可以參考圖 5-9 所示的操作步驟。 圖 5-9. Assistant 彈出式選單

Xcode 會在助理編輯器(Assistant Editor )中顯示你的 App UI 的預覽。預設上,它是顯示 iPhone 8 裝置的預覽圖。你可以點選助理編輯器左下角的「+」按鈕來加入 iOS 裝置(例如:iPhone SE / 8 Plus)來預覽。如果你想要觀察在橫向模式的顯示狀態,只要點選「旋轉」按鈕即可。這個預覽功能對於設計 App 的使用者介面而言是非常實用的,你可以將 Storyboard 做些改變(例如:加入另一個按鈕至視圖中),同時在預覽圖中觀察 UI 有何相對應的變化, 如圖 5-10 所示。

圖 5-10.助理編輯器中的Storyboard 預覽圖
圖 5-10.助理編輯器中的Storyboard 預覽圖

若是你想要釋出更多的畫面空間來預覽,按下 command + option鍵,然後按下來隱藏工具區。

pre> Quick tip: 當你在預覽助理中加入更多的裝置,Xcode 可能無法同時容納各種大小的裝置在同一畫面中。如果你使用觸控板(trackpad),你可以使用兩根手指在預覽畫面上左右滑動來導覽。如果你使用的是滑鼠加上滾輪,則只要按住 shift 鍵來水平滾動即可。</pre>

加上一個標籤

現在你對 Auto Layout 應該有了概念,我們來試著加上一個標籤到視圖的右下方,並了解該如何定義這個標籤的約束條件。iOS 中的標籤通常是用於顯示一些文字與訊息。

在介面建構器中,從元件庫(Object Library )拖曳一個標籤,並將之置放到視圖的右下角。在標籤上點選兩下,將標題改為「Welcome to Auto Layout」,然後按下 command+= 來自動調整標籤大小,或者任何你想放的文字皆可,如圖 5-11 所示。

圖 5-11. 加入一個標籤至視圖中
圖 5-11. 加入一個標籤至視圖中

如果助理編輯器中的預覽圖已經打開,你應該能夠即時見到 UI 的更新,如圖 5-12 所示。如你所見,在沒有為標籤定義任何約束條件的情況下,除了 iPhone 8 與 8 Plus之外,你無法在所有的裝置上正確地顯示標籤。

圖 5-12. 標籤無法正確顯示
圖 5-12. 標籤無法正確顯示

那麼要怎麼解決這個問題呢?很明顯的,我們必須要設定一些約束條件來讓它能夠正確運作。問題是:我們要加入什麼約束條件呢?

我們先試著用文字來描述這個標籤的需求。你可以像這樣來描述:

這個標籤應該要置於視圖的右下角。

這樣敘述沒有問題,不過還不夠精確。更精確描述這個標籤的位置的敘述如下:

這個標籤位於距離視圖右側邊距 0 點的位置,且距離視圖底部 20 點。

這樣好多了。當你精確地描述一個項目的位置,你可以很容易想到佈局約束條件。這個標籤的約束條件是:

  1. 這個標籤距離視圖右側邊距為 0 點。
  2. 標籤距離視圖底部是 20 點。

在 Auto Layout 中,我們以這樣的約束條件作為間距約束條件。想要建立這些間距約束條件,你可以使用佈局按鈕中的「Add new constraints」按鈕。不過這次我們使用 control 鍵加上拖曳的方法來應用 Auto Layout。在介面建構器中,你可以按著 control 鍵,從一個項目拖曳至自己,或者拖曳至另一個你想要加入約束條件的項目。

要加入第一個間距約束條件,按住 control 鍵並從標籤拖曳至右側,直到視圖變成藍色為止。現在放開按鈕,你會見到一個彈出式選單,顯示一串約束條件選項。選取「Trailing space to Safe Area」來加入從標籤至視圖右側邊距的間距約束條件,如圖 5-13 所示。

圖 5-13. 使用 control 鍵加上拖曳來加入第一個約束條件
圖 5-13. 使用 control 鍵加上拖曳來加入第一個約束條件

在文件大綱視圖中,你會見到新的約束條件。介面建構器現在以紅色顯示約束線,並指出還有一些漏掉的約束條件。這很正常,因為我們還沒有定義第二個約束條件。

現在按住 control 鍵,從標籤拖曳至視圖底部。釋放按鈕並在彈出式選單中選取「Bottom Space to Safe Area」,如此一來,便建立了一個從標籤至視圖底部佈局導引的間距約束條件,如圖 5-14 所示。

圖 5-14. 使用 control 鍵加上拖曳來加入第二個約束條件
圖 5-14. 使用 control 鍵加上拖曳來加入第二個約束條件

在你加入了這兩個約束條件後,所有的線都變成藍實線了。當你預覽 UI 或者在模擬器中執行 App,這個標籤在所有螢幕尺寸中應該都能夠正確顯示,即使在橫向模式也沒有問題,如圖 5-15 所示。

圖 5-15. 現在 UI 能夠支援所有不同尺寸的螢幕
圖 5-15. 現在 UI 能夠支援所有不同尺寸的螢幕

很棒,你已經正確地定義約束條件,不過,你可能會注意到在文件大綱中的黃色指示,你將會發現一個跟本地化(localization)有關的佈局警告。

這是什麼呢?

這是在 Xcode 9 中介面建構器的新功能,我們的 App目前顯示是支援英文,所以我們所定義的約束條件是用英文版本,但如果要支援其他語系呢?目前的佈局對於其他語言依然能夠適用嗎(譬如阿拉伯文)?

在 Xcode 9,介面建構器將會檢視你的佈局約束條件並了解是否相容所有語言,如果發現問題它會發出一個本地化警告,你可以選擇第二個選項來加入前端約束條件(leading constraint)。

圖 5-16. 跟本地化有關的佈局問題
圖 5-16. 跟本地化有關的佈局問題

安全區域

在文件大綱,你有注意到一個稱作 Safe Area(安全區域) 的項目嗎?你記得我們之前所定義的間距約束條件跟安全區域有關嗎?我們定義兩個間距約束條件:

  1. 後緣間距(Trailing space)至安全區域
  2. 底部間距(Bottom space)至安全區域

那麼什麼是安全區域呢?

安全區域是在 Xcode 9 所導入用來替代舊版 Xcode 中頂部與底部佈局導引(top & bottom layout guides)的新功能,與其用文字來解釋這些名詞,我們直接來告訴你什麼是安全區域。

至文件大綱,選取 Safe Area,藍色的部分就是安全區域,安全區域實際上是一個佈局導引,清楚地呈現不包含列(bar)以及其他內容的視圖,如圖 5-17 所示,除了狀態列(status bar)外的整個視圖都是安全區域。

圖 5-17.安全區域
圖 5-17.安全區域

這個安全區域佈局導覽幫助開發者很容易地處理約束條件,因為這個安全區域在遇到被導覽列(navigation bar)或其他內容所覆蓋時會自動更新。

看一下圖 5-18,這個 Hello word 按鈕定義為位於安全區域頂部下方 20 點,如果這個視圖沒有導覽列或標籤列(tab bar),則安全區域是除了狀態列外的整個視圖,因此按鈕是位於狀態列下 20 點。

圖 5-18. 安全區域會自動調整
圖 5-18. 安全區域會自動調整

如果視圖中包含了一個導覽列,不論它是使用標準標題或者在 iOS 11的大標題,這個安全區域會自動地調整,這個按鈕便會移至導覽列下方,因此,只要 UI 元件的約束條件是相對於安全區域佈局導覽,即使你在介面中加入導覽列或者標籤列,你的介面會正確佈局。

編輯約束條件

現在這個「Welcome to Auto Layout」標籤距離安全區域右側邊距為 16 點。那麼若是你想要在標籤和視圖的右側邊距間加入一些間距呢?介面建構器提供一個方便的方式來編輯約束條件的常數。

你可以在文件大綱視圖挑選約束條件或者直接選取約束條件。在屬性檢閱器(Attributes Inspector )中,你可以找到這個約束條件的屬性, 包括了關聯性(Relation )、常數(Constant )以及優先權(Priority )。常數(Constant ) 現在是設定為 16,你可以將它修改為 30 來加入一些間距,如圖 5-19 所示。

圖 5-19. 使用屬性編輯器編輯約束條件
圖 5-19. 使用屬性編輯器編輯約束條件

另外,你也可以在約束條件點擊兩次,然後透過彈出選單來編輯它的屬性。

圖 5-20. 雙擊約束條件來進行編輯
圖 5-20. 雙擊約束條件來進行編輯

你的作業-加入標籤並加上約束條件

現在,我希望你對如何佈局你的 App UI 以及讓它能夠相容各種尺寸有一些基本概念了。在我們進到下一章之前,我們來做一個簡單的作業,我只要你加入另外兩個表情符號標籤至視圖中,圖 5-21 為預期的結果,這裡有幾個提示:

  • 這個「笑臉」表情符號標籤應該距離安全區域頂部 10 點,並水平置中。

  • 這個「調皮鬼」標籤有兩個間距約束條件。

你可以在屬性檢閱器,透過編輯它的 Font 選項來調整標籤的字型大小,不過即使你不知道該怎麼做也沒關係,我將在接下來的章節告訴你,現在先專注在約束條件的定義。 圖 5-21. 所期望的 App 佈局

本章小結

在本章中,我們學到了Auto Layout 的基礎內容。是的,這只是基礎而已,因為我不想學習 Auto Layout 後就馬上把你嚇跑。當我們更深入建立真實的 App 時,我們將繼續探討 Auto Layout 的其他功能。

多數的初學者(即使是一些有經驗的 iOS 程式設計師)都會避免使用 Auto Layout,因為它看起來會讓人搞不清楚。但當你完全了解我在本章中所介紹的內容時,你即將踏上成為一個優秀 iOS 開發者的道路。

最早的 iPhone 是在 2007 年推出,經過這些年後,iOS 的發展已經有了許多的變化與進步,不像以前你的 App 只需要在 3.5 英吋無 Retina 螢幕的裝置上運作這麼單純,現在你必須滿足不同螢幕解析度及畫面尺寸,這也是為何我以整個章節的篇幅介紹 Auto Layout 的緣故。

請花點時間來消化一下這些內容吧!

本文摘自《iOS 11 App程式設計實戰心法》一書,博碩授權轉載。如果你想更深入學習Swift程式設計,請到天瓏博客來或其他書局購買完整版本,全書範例檔皆可下載。而你亦可以從AppCoda網站購買完整電子版。

results matching ""

    No results matching ""