iOS 12 Auto Layout界面自動佈局系列2-使用Xcode的Interface Builder添加布局約束

上一篇文章《iOS 12 Auto Layout界面自動佈局系列1》簡要介紹了iOS界面佈局方式的前世今生。本篇文章將詳細介紹如何使用自動佈局實現不同屏幕尺寸的適配。

 

添加自動佈局約束(下文簡稱約束)有以下幾種方式:

 

  • 使用Xcode的Interface Builder界面設計器添加並設置約束
  • 通過系統原生的NSLayoutConstraint逐條添加約束
  • 通過可視化格式語言VFL添加約束
  • 使用第三方類庫(如Masonry)添加約束

 

本系列文章將以一個簡單的例子來演示如何使用這幾種方式添加約束,如下圖所示。程序的界面主要由三部分組成,最上面是一張蘋果logo圖片,下面是可以滾動的區域,包含公司名稱和詳細介紹。豎屏:

橫屏:

 

打開Xcode(本文使用的版本爲10.1),新建項目(快捷鍵⇧⌘N),選擇iOS -> Application -> Single View App。項目可任意命名(如AutoLayoutXcode),語言選擇Objective-C。

點擊Next完成項目創建。打開Main.storyboard,拖入一個Image View,一個Scroll View以及兩個Label,並將兩個Label作爲ScrollView的子視圖。爲了便於識別,將Image View的名稱改爲Logo Image,兩個Label的名稱修改爲Name Label與Description Label。

 

要想正確定位Logo Image,我們需要添加4個約束,分別是:

  • Logo Image左側與其父視圖左側對齊
  • Logo Image右側與其父視圖右側對齊
  • Logo Image頂部與其父視圖頂部對齊
  • Logo Image的高度爲其父視圖高度的一半

於是選中Logo Image,點開設計器下方的Add New Constraints菜單,在彈出菜單上方取消勾選Constrain to margins(否則會有間距),並設置左側、右側與頂部的約束值均爲0(注意要將工字型約束標記由虛線點亮爲實線),最後點擊彈出菜單下面的Add 3 Constraints按鈕,這樣就添加了上述三個對齊約束,如下圖所示。

 

在Xcode右側的Size Inspector中可以查看當前選中界面元素的尺寸及所添加的約束。選中Logo Image並點擊Size Inspector,可以在下圖中紅色圓角矩形區域內看到剛剛添加的三個約束,如下圖所示。

三條藍線分別表示尾部、頭部與頂部對齊約束。下面的列表也詳細列出了這三條約束:

  • Align Trailing to: Safe Area表示所選視圖與安全區域尾部對齊
  • Align Leading to: Safe Area表示所選視圖與安全區域頭部對齊
  • Align Top to: Safe Area表示所選視圖與安全區域頂部對齊

這裏額外解釋一下,安全區域是iOS 11引入的新概念,簡單起見可暫且認爲其等同於控制器的主視圖(關於安全區域,可參考我的另一篇博客《關於iOS中的佈局嚮導(Layout Guide)和安全區域(Safe Area)》)。“頭部”與“尾部”針對當前系統的語言文字方向。絕大多數情況下,語言文字方向都是從左到右,因此“頭部”等同於“左側”,“尾部”等同於“右側”。但是,某些語言文字方向爲從右到左,例如阿拉伯語,則其“頭部”對應“右側”,“尾部”對應“左側"。鼠標雙擊Align Trailing to: Safe Area約束會顯示該約束的詳細信息,如下圖所示。

 

回憶一下上一篇文章中關於約束的介紹,約束就是一個線性關係:

y = m * x + c

圖中的First Item對應公式中的y,表示因變量,這裏顯示的是Safe Area.Trailing表示安全區域尾部。Relation對應公式中的=,表示相等關係,這裏顯示的是Equal即相等(這裏爲什麼會有下拉菜單?點開你會發現,除了=之外,還可以設置爲>=或者<=,我們以後再詳細講解)。Second Item對應公式中的x,表示自變量,這裏顯示的是Logo Image.Trailing表示Logo圖片的尾部。Multiplier對應公示中的m,表示縮放比例係數,這裏的值爲1。Constant對應公示中的c,表示偏移常量,這裏的值爲0。所以完整串下來就很清楚地表達了安全區域尾部與圖片尾部對齊這樣一個線性關係。

注意,建立約束的雙方是對等的,既可以說y相對於x發生變化,亦可以說x相對於y發生變化,所以First Item與Second Item是可以互換的,即反函數:

x = 1/m * y - c/m

點擊First Item或者Second Item下拉菜單,選擇Reverse First And Second Item即可交換雙方的位置。

交換後的Multiplier與Constant會自動根據反函數公式計算得出。

交換前後的效果是一樣的。

注意到左側文檔結構窗口(Document Outline)右上角出現了一個紅色按鈕,表示當前界面存在佈局約束錯誤。

點擊該按鈕,Xcode將列出錯誤和警告。錯誤爲紅色圓形按鈕,警告爲黃色三角按鈕,點擊後會彈出建議的解決方案。

我們現在僅爲Logo Image添加了3個約束,還缺少確定圖片最下面位置的約束,即上圖中所指出的缺少高度約束(Missing Constraints:Logo Image,Need constraints for: height)。這種由於缺少約束而導致的錯誤,被稱作“二義性錯誤”(Ambiguity Error)。此時如果點擊Add Missing Constraints按鈕,Xcode會自行添加缺失的約束,但可能並非如我們所願,甚至造成混亂。因此我們點擊Cancel,自己添加約束。

我們希望圖片總能夠佔據上半部分屏幕,因此可以在圖片與安全區域之間建立高度約束。在文檔結構窗口中,鼠標單擊選中Logo Image,按住Control鍵(或者按住鼠標右鍵)拖拽到Save Area上。

鬆開鼠標,在彈出的菜單中選中Equal Height。

保持Logo Image選中,在Size Inspector窗口中雙擊Equal Height to: Safe Area約束,修改Multiplier的值爲0.5。

現在Logo Image的4個約束就齊了。由於我們尚未向ScrollView和Label添加約束,所以Storyboard文件還是會報二義性錯誤,我們先暫時忽略這些錯誤。

接着建立Scroll View的約束,它與安全區域頭部、尾部、底部對齊,並且Logo Image與Scroll View的垂直間距爲0。同理打開Add New Constraints菜單,取消勾選Constrain to margins,將4個方向的值設置爲0(暫時先不點擊Add 4 Constraints按鈕),如下圖所示:

 

Xcode會採取就近原則自動選取因變量x,但這有可能並不是我們希望的。例如,我們希望Scroll View頂部和Logo Image底部對齊,於是點擊下圖中頂部約束的下拉菜單,會列出可供選擇的自變量。這裏會出現兩種情況:

  • 一種可能是,菜單中列出了View、Safe Area和Logo Image,且默認選中了Logo Image,如下圖。

那麼恭喜你,你可以直接點擊Add 4 Constraints,Scroll View的4個約束就加好了。

  • 另一種可能是,菜單中只列出了View(控制器主視圖)和Safe Area,並未列出Logo Image,如下圖。

此時無法添加想要的頂部對齊約束,那麼先暫時點擊頂部的紅色工字型將其變爲虛線(如下圖紅圈),然後點擊Add 3 Constraints。

菜單中未出現Logo Image的原因是Scroll View和Logo Image這兩個視圖重疊了(上圖中雙向箭頭區域),兩者間距爲負值,所以Xcode的就近原則不適用於間距爲負值的情況。解決辦法是將Scroll View與Logo Image二者垂直間距變爲正值,將Scroll View的頂部位於Logo Image底部的下方,即二者的垂直間距爲正值,這時再點擊Add New Constraints菜單添加頂部約束就可以了。

現在Scroll View的約束添加完畢。接着我們爲Name Label添加約束,將其頭部、頂部與尾部與Scroll View的對應部分對齊,並限定其高度爲20。除了使用Add New Constraints菜單添加約束外,還可以通過拖拽添加約束,我們就來試試這種方法。

右鍵點擊Name Label且不鬆開右鍵,拖拽到Scroll View並鬆開鼠標,彈出菜單。按住⇧並點擊Leading Space to Container、Top Space to Container、Trailing Space to Container,按下enter鍵添加頭部、頂部、尾部約束。

右鍵點擊Name Label並拖拽到自己身上,鬆開鼠標,在彈出的菜單中選擇Height,添加高度約束。

 

這種方式會以當前界面設計器中的位置尺寸來設置約束的常量值,如果需要可以再修改常量。選中Name Label,在Size Inspector中可以看到剛剛添加的4個約束的常量值都不正確。

點擊Trailing Space to: Superview右側的Edit按鈕,在彈出的窗口允許修改約束的m和c值。此處將Constant的值修改爲0。

同理,將Leading Space to: Superview和Top Space to: Superview的Constant值修改爲0,將Height Equals:的Constant值修改爲20即可。

選中Name Label,在Attributes Inspector窗口中設置Label的Text屬性爲“蘋果公司”,設置Background爲綠色。

同樣爲Description Label添加約束,將其頭部、底部、尾部與Scroll View的對應部分對齊,並且頂部與Name Label的底部垂直間距爲0。在Attributes Inspector窗口中設置Label的Text爲:

蘋果公司(Apple Inc. )是美國的一家高科技公司。由史蒂夫·喬布斯、斯蒂夫·沃茲尼亞克和羅·韋恩(Ron Wayne)等三人於1976年4月1日創立,並命名爲美國蘋果電腦公司(Apple Computer Inc. ), 2007年1月9日更名爲蘋果公司,總部位於加利福尼亞州的庫比蒂諾。
蘋果公司創立之初主要開發和銷售的個人電腦,截至2014年致力於設計、開發和銷售消費電子、計算機軟件、在線服務和個人計算機。蘋果的Apple II於1970年代助長了個人電腦革命,其後的Macintosh接力於1980年代持續發展。該公司硬件產品主要是Mac電腦系列、iPod媒體播放器、iPhone智能手機和iPad平板電腦;在線服務包括iCloud、iTunes Store和App Store;消費軟件包括OS X和iOS操作系統、iTunes多媒體瀏覽器、Safari網絡瀏覽器,還有iLife和iWork創意和生產力套件。蘋果公司在高科技企業中以創新而聞名世界。
蘋果公司1980年12月12日公開招股上市,2012年創下6235億美元的市值記錄,截至2014年6月,蘋果公司已經連續三年成爲全球市值最大公司。蘋果公司在2014年世界500強排行榜中排名第15名。2013年9月30日,在宏盟集團的“全球最佳品牌”報告中,蘋果公司超過可口可樂成爲世界最有價值品牌。2014年,蘋果品牌超越谷歌(Google),成爲世界最具價值品牌 。

設置Lines的值爲0,設置Background爲黃色。

Xcode 8.0添加了實時預覽功能,可以在不啓動模擬器/真機的情況下預覽不同設備橫豎屏的界面情況。注意到設計器下方的工具條:

這裏可以選擇不同的設備(iPad、iPhone),以及選定屏幕方向(豎屏、橫屏),設計器會根據不同的設置顯示對應界面。

除此之外,Xcode的Preview工具還支持同時預覽不同屏幕大小的界面情況,方便進行對比。打開Assistant Editor,點擊快速跳轉下拉菜單:

選擇Preview -> Main.storyboard:

在右側預覽窗口中就可以看到在不同設備上的效果。可以點擊預覽窗口左下角的+按鈕,在彈出菜單中添加需要預覽的設備。

現在我們添加Logo Image的圖片。下載蘋果Logo圖片apple.jpg,並將其拖入項目中。文件下載地址:https://pan.baidu.com/s/1b5AqDo 密碼: e4ff

選中Logo Image,在屬性窗口(Attributes Inspector)的Image View中,將Image設置爲apple.jpg,將Content Mode設置爲Aspect Fit,這樣就能根據Image View的大小來調整圖片的縮放方式。

現在不妨在模擬器中實際運行一下程序,發現Scroll View變成了橫向滾動而非縱向滾動,這並不是我們想要的效果。

 

可是我們已經把每個視圖的4個必要約束都添加了,怎麼還會出現這樣的問題呢?

是這樣的,當使用自動佈局爲Scroll View添加約束時,除了需要確定ScrollView本身的位置尺寸之外,還需要明確ScrollView的ContentSize大小。對於上述例子,Scroll View本身會佔用下半部分屏幕,但是其ContentSize的大小是不確定的,所以會出現異常滾動效果。因此我們還需要爲兩個Label確定寬高,這樣才能計算出ContentSize。按住⌘鍵,在文檔結構窗口中選中Logo Image、Name Label與Description Label,點擊Pin按鈕,在彈出的窗口中選中Equal Width,這樣就使得兩個Label的寬度總與Image View的寬度相等,即Scroll View的ContentSize的寬度總是和Scroll View本身的寬度相同,因此就不會出現橫向滾動的情況了。

再次運行,現在只能縱向滾動了。

程序最終項目文件鏈接:https://github.com/puckerxp/AutoLayoutSeries,在AutoLayoutXcode目錄下。

通過這個例子我們不難發現,其實自動佈局的概念並不難,而且它能夠很好地解決多設備界面適配與屏幕旋轉處理等工作。而且在這幾種添加約束的方式當中,使用Xcode的Interface Builder來可視化地創建約束,以及使用預覽工具來實時調整約束,這種方式是最簡單直觀而且最常用的方式。

在本系列後續文章中,將會介紹如何通過代碼創建NSLayoutConstraint對象,以及如何使用VFL語言來添加約束。

如果你對我寫的東西有任何建議、意見或者疑問,請到我的博客留言:

Puzhi的CSDN博客

 

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