UIStackView上手教程

Andy矢倉發表於2018-08-24

原文:UIStackView Tutorial: Introducing Stack Views

最初教程由Jawwad Ahmad原創。Kevin Colligan更新支援iOS 11、Xcode 9和Swift 4。

轉載註明:www.rockerhx.com/2018/08/21/…

iOS開發當中是不是遇到需要動態新增或者刪除檢視元素的需求。你是上基hub去嗨一遍第三方庫還是自行擼frame,或者用Auto Layout的約束更新。就這點破需求,反正我是堅決不選前兩者,即便是萬不得已,最多也是更新約束(雖然Auto Layout的所見即所得極大縮短了開發耗時,增加我擼貓的快樂時光,但不得不承認我是很反感用程式碼去改約束,視覺化編碼還要去code約束,腦子有病!!!)。 處理這類需求,總之一句話。

UIStackView上手教程

好在,現在大傢伙應該都只支援到iOS9了,用上UIStackView來處理這類需求簡直是美滋滋,艾瑪真香~~~ 在本教程中,闊以瞭解UIStackView如何提供一種簡單的方式來處理水平或垂直佈局。還闊以瞭解如何通過使用對齊、分佈和間距等屬性來獲取檢視,以便自我調整方便自適應。

本教程假定觀者基本熟悉Auto Layout。如果不熟悉,請移步傳送門Beginning Auto Layout

教程開始

UIStackView上手教程

在這份UIStackView教程中,我們將使用一個名為“Vacation Spots”的應用程式。這個簡單的應用闊以展示度假地點的一些基礎資訊。 不要方方髒髒的就開始動手,因為有幾個問題需要我們先用UIStackView來處理下,而且比單獨使用自動佈局要簡單得多。首先下載這個UIStackView教程的入門專案。開啟專案並在iPhone模擬器上執行。你會看到一份度假地點清單。

UIStackView上手教程

點選London那一欄,進入倫敦的資訊檢視。乍一看,好像還不錯,但有幾個問題。

  • 看看檢視底部的一排按鈕。他們目前的位置是固定的,所以他們不適應螢幕寬度。不信按Command - left將模擬器橫向來看看。
    UIStackView上手教程
  • 點選WEATHER旁邊的Hide按鈕。它成功地隱藏了文字,但是它沒有重新定位它下面的部分,留下一塊空白。
    UIStackView上手教程
  • 可以改進這些部分的展示順序。如果what to see部分正好位於why visit部分之後,而不是在兩者之間有weather部分,這將會更合乎邏輯。
  • 在橫屏模式下,按鈕的底部離檢視的底部邊緣太近了一點。如果能減少元素之間的間距,那就更好看。

既然我們已經羅列好了改進工作,那就動手開始吧!!!

開啟Main.storyboard。第一次這樣做時,會要求您選擇初始裝置檢視。這個檢視在執行時沒有效果,它針對不同的裝置調整大小,也只是讓故事板的使用變得更加容易。iPhone 7或者8就行了。

UIStackView上手教程
你闊以隨時點選故事板的操作區域的正下方,選擇View As: iPhone 7 ,或者隨便改變也行。
UIStackView上手教程
現在開啟
Spot Info View Controller
看看,這東一塊西一坨的顏色是什麼鬼?
UIStackView上手教程

這些標籤和按鈕的各種背景色,執行時會被清除。在Storyboard中,它們只是視覺上的輔助,幫助顯示改變StackView的各種屬性將如何影響其嵌入檢視的佈局。

你現在不用管這些,如果在執行應用程式的時候你真的想看到背景色,你可以在SpotInfoViewController內部的**viewDidLoad()**中臨時註釋出以下幾行。

// Clear background colors from labels and buttons
for view in backgroundColoredViews {
    view.backgroundColor = UIColor.clear
}
複製程式碼

此外,所有的UI元素都使用了明確的佔位內容,以便連結屬性的時候更加明確方便,減小連錯的可能性。

@IBOutlet weak var whyVisitLabel: UILabel!
複製程式碼

叨逼叨完了,let’s get started!

第一次

使用stack view第一件事是修復按鈕底部行之間的間距。stack view可以以各種方式沿其軸分佈其檢視,其中一種方式是每個檢視之間的間距相等。 蘋果為了推廣新控制元件,我們可以直接把想要的處理的控制元件元素直接一鍵壓入stack view。開啟Spot Info View Controller故事版場景,按住Command選中底部三個按鈕。

UIStackView上手教程

點選右下角Show Document Outlin

UIStackView上手教程

在左側控制元件集列表內確認下是不是選對了按鈕:

UIStackView上手教程

選中後,單擊故事板畫布右下角自動佈局工具欄中的“新建堆疊”按鈕:

UIStackView上手教程

按鈕將嵌入到新的堆疊檢視中:

UIStackView上手教程

現在出現了約束警告,stack view只是一種排版形式,是繼承自UIView,它也是需要約束來確定frame,只有確定好自身的frame以後才能處理內部控制元件佈局。

stack view中嵌入控制元件時,將刪除對其的任何約束。例如,在將按鈕嵌入stack view之前,Submit Rating按鈕的頂部有一個連線到Ratinglabel的垂直間距約束:

UIStackView上手教程

點選選中Submit Rating按鈕可以看到它不在包含任何約束。

UIStackView上手教程

也闊以通過**Size inspector (⌥⌘5)**來檢視控制元件約束情況:

UIStackView上手教程

接下來我們需要為stack view新增約束控制,如果整個頁面的控制元件太多導致不好選中某個控制元件,直接從左側的控制元件列表就好。

UIStackView上手教程

另外有個小技巧,按住Shift再單擊右鍵,Xcode會幫大忙。

UIStackView上手教程

最後通過右下角的Auto Layout toolbar新增約束即可。

UIStackView上手教程

保持Constrain to margins選中,然後新增如下約束。

Top: 20, Leading: 0, Trailing: 0, Bottom: 0
複製程式碼

按照如圖所示輸入數字直接tab就好,簡單而快速的新增約束才是敏捷開發的首選。

UIStackView上手教程

控制元件之間現在看起來像是這樣,stack view會拉伸第一個控制元件來填充空間。

UIStackView上手教程

決定stack view內部控制元件的分佈屬性為distribution。目前,它被設定為Fill,這意味著被包含的控制元件將沿著其軸完全填充。為了實現這一點,stack view將只拉伸其中一個檢視來填充額外的空間;具體來說,它會拉伸content hugging優先順序最低的檢視,或者如果所有控制元件優先順序相同,它拉伸第一個檢視。

然鵝,我們只是向他們等距分佈就好。切換到Attributes inspector屬性編輯器,把Distribution的值從Fill改到Equal Spacing即可:

UIStackView上手教程

跑一下看看底部按鈕是不是等距分佈了,無論是豎屏還是橫盤都是穩穩的,不過還不夠完美,當你切換到小螢幕上,比如使用iPhone SE模擬器來跑一下看看。

UIStackView上手教程

好在蘋果也考慮到這種情況,我們改變Distribution屬性,從Equal Spacing改為Fill Proportionallyspacing值改為10

UIStackView上手教程

現在,在iPhone SE模擬器上再跑一次,這次必須棒棒噠。

UIStackView上手教程

咋樣,第一次上手stack view484真香,so easy。

UIStackView上手教程

在沒有stack view,你必須使用間隔檢視來佔位,每對按鈕之間有一個佔位。要正確定位間隔檢視,您必須向所有間隔檢視新增等寬約束以及許多附加約束。 它看起來會像下面這樣。為了在螢幕截圖中可見,間隔檢視被賦予了淺灰色背景:

UIStackView上手教程

如果只是偶爾這麼做一次其實還好,如果做多了,小夥子身體可吃不消啊。特別是動態新增檢視這種。比如隱藏例子中的WEATHER這種。

現在我們只是簡單的設定間距值,如果你想在某個檢視中設定特別的間距,在iOS11裡提供的新的Api: setCustomSpacing:afterView

沙場老司機

經過上面的演練,下面我們就能很輕鬆的把SpotInfoViewController裡需要的結構轉換成stack view

評級部分

選中評級RATING部分的兩個控制元件。

UIStackView上手教程

接著還是同樣的點選Stack按鈕將其嵌入到stack view裡。

UIStackView上手教程

這次我們只需要新增三個約束即可:

Top: 20, Leading: 0, Bottom: 20
複製程式碼

UIStackView上手教程

spacing值這是為8

UIStackView上手教程

你可能會看到一個錯位的檢視警告,如下圖所示,其中星星標籤已經超出了檢視的範圍(這種警告可能因為某些beta版本的原因才會出現,沒出現那就恭喜你繼續):

UIStackView上手教程

如果確定自己的約束是正確的,因為Xcode某些版本的bug引起的檢視錯位,直接用右下角的Refresh Layout按鈕矯正即可。

UIStackView上手教程

現在看起來就正常了。

UIStackView上手教程

還原檢視

如果發現有的時候手殘,或者是處於實驗性目的,多上了stack view,直接選中需要撤銷的控制元件,按住Option,左擊StackUnembed即可撤銷。

UIStackView上手教程

或者選中控制元件從選單Editor \ Unembed撤銷也行。

試試第一個垂直方式

現在我們來建立垂直方式的堆疊檢視,選中WHY VISIT和**<whyVisitLabel>**兩個文字控制元件。

UIStackView上手教程

Xcode會根據控制元件的分佈排列來確實方向,就比如現在這樣,直接生成的就是垂直分佈的堆疊檢視。

UIStackView上手教程

現在我們來確定約束,只需要把這部分的上左右約束都設定為0,只不過底部約束的物件是相對WEATHER控制元件,間距是20,一看即懂。

UIStackView上手教程

設定完後預設對齊是左對齊,如下圖所示:

UIStackView上手教程

對齊屬性

對齊屬性確定堆疊檢視如何垂直於其軸佈局。對於垂直堆疊檢視,可以設定的對齊方式為:

  • 填充·Fill
  • 靠左對齊·Leading
  • 居中對齊·Center
  • 靠右對齊·Trailing

水平堆疊檢視對齊屬性的值略有不同:

UIStackView上手教程

水平佈局的對齊方式分別為:

  • 頂部對齊·Top
  • 靠左對齊·Leading
  • 底部對齊·Bottom
  • 靠右對齊·Trailing
  • 第一元素基準線·FirstBaseline:意思是以第一個UI元素的的內容基準線為準,後面元素內容以此基準線對齊。
  • 最後元素基準線·LastBaseline:意思是以最後一個UI元素的的內容基準線為準,前面元素內容以此基準線對齊。

大家闊以選中剛才設定好的垂直堆疊檢視,調整下對齊屬性看下變化就淺顯易懂了。 填充·Fill:

UIStackView上手教程
靠左對齊·Leading:
UIStackView上手教程
居中對齊·Center:
UIStackView上手教程
靠右對齊·Trailing:
UIStackView上手教程

跑起來看一下佈局穩當冇問題。

轉換“what to see”部分

這部分轉換和前面一節沒啥區別,直接操作關鍵點即可。

  • 首先選中WHAT TO SEE和**<whatToSeeLabel>**兩個文字元素。
  • 其次壓入堆疊檢視。
  • 對齊方式選中填充·Fill。
  • 最後設定好如下約束即可。
Top: 20, Leading: 0, Trailing: 0, Bottom: 20
複製程式碼

設定完以後大概就長這樣:

UIStackView上手教程

轉換“weather”部分

由於需要隱藏天氣,所以這部分是比較難搞的。

我們先把這部分的所有元素都壓入堆疊檢視。先選中WEATHER文字欄和Hide按鈕,壓入水平堆疊檢視,然後在按住Command選中下面的**<weatherInfoLabel>**文字欄部分,將水平堆疊檢視和這部分一起壓入垂直堆疊檢視。

UIStackView上手教程

其實可以發現,水平的堆疊檢視被Hide按鈕給頂開了,如果覺得不喜歡,闊以選中底部對齊的方式來看看效果。

UIStackView上手教程

也還是不太滿意,那根據我的經驗,要不就是修改水平堆疊檢視內UI元素的約束優先順序,要不就是把Hide按鈕給拆出去,單獨處理約束。為了容易理解我們還是單獨處理。

自行撤回到天氣部分的原始轉態。選中WEATHER和**<weatherInfoLabel>**兩個文字欄部分:

UIStackView上手教程

將其壓入垂直堆疊檢視:

UIStackView上手教程

然後設定好如下約束:

Top: 20, Leading: 0, Trailing: 0, Bottom: 20
複製程式碼

對齊方式為填充:

UIStackView上手教程

因為Hide按鈕被拆出去,所以我們需要對其新增約束以保證按鈕位置的正確性。因為需要設定約束的相對控制元件為WEATHER文字欄,所以我們還得再改造改造。 直接在控制元件列表欄選中WEATHER或使用組合拳Control-Shift-click

UIStackView上手教程

壓入堆疊檢視:

UIStackView上手教程

對齊方式·Alignment選中為靠左對齊·Leading排版·Axis確定為垂直·Vertical排版:

UIStackView上手教程

執行看看是啥情況:

UIStackView上手教程

我頂你個肺,啥情況,按鈕跑偏了?實際上是我們拆出Hide按鈕之後忘記給設定約束。 按住Control選中Hide按鈕拖動指向到WEATHER文字欄新增約束:

UIStackView上手教程

只要完成如下兩條約束,間距和縱向位置的約束即可:

UIStackView上手教程

再重新跑一下,這回就必須妥當了。

UIStackView上手教程

堆疊化

在左側控制元件列表裡選中我們之前所有做個堆疊化的控制元件:

UIStackView上手教程

全部壓入堆疊:

UIStackView上手教程

然後給最外層堆疊檢視新增約束,確保勾選上Constrain to margins,四邊邊距約束為0即可。 然後間隙·Spacing設定為20對齊方式·Alignment設定為填充·Fill

UIStackView上手教程

再次執行還是會有剛才那個屌問題。

UIStackView上手教程

只要記住如果有外設相對控制元件的約束,只要堆疊化,約束就會被幹掉,只能再次新增了:

UIStackView上手教程

完善層級

最後我們需要把what to see的部分挪動到weather部分上面去,最好的方式是在左側控制元件列表裡拖動:

UIStackView上手教程

如果在Storyboard裡直接去拖動,很可能會因為選錯控制元件元素而導致打亂結構。

根據螢幕大小配置間隙

由於在橫屏的情況下,垂直方向上的空間比較珍貴,所以針對橫屏,把間隙改為10比較穩妥。 找到間隙·Spacing的左側的**+**號按鈕:

UIStackView上手教程

選擇Any Width > Compact Height,然後新增·Add Variation

UIStackView上手教程

wAny hC欄新增值為10即可:

UIStackView上手教程

最後執行一下看看,包括橫屏(⌘←)也看看,484看起來比較舒爽了。

UIStackView上手教程

動畫

當前的隱藏和呈現動畫效果看起來有木有點生硬,感覺怪怪的。我們還是新增點動畫讓細節看起來比較絲滑為妙。 開啟SpotInfoViewController.swift,定位到updateWeatherInfoViews(hideWeatherInfo:animated:)方法,現在看起來長這樣:

weatherInfoLabel.hidden = shouldHideWeatherInfo
複製程式碼

替換成如下程式碼即可:

if animated {
    UIView.animate(withDuration: 0.3) {
        self.weatherInfoLabel.isHidden = shouldHideWeatherInfo
    }
} else {
    weatherInfoLabel.isHidden = shouldHideWeatherInfo
}
複製程式碼

找到@IBAction func weatherHideOrShowButtonTapped(_ sender: UIButton)方法,替換成如下程式碼:

@IBAction func weatherHideOrShowButtonTapped(_ sender: UIButton) {
	let shouldHideWeatherInfo = sender.titleLabel!.text! == "Hide"
	updateWeatherInfoViews(hideWeatherInfo: shouldHideWeatherInfo, animated: shouldHideWeatherInfo)
	shouldHideWeatherInfoSetting = shouldHideWeatherInfo
}
複製程式碼

這樣跑一下看,隱藏起來就不會辣麼尬了。。。

寫在最後

一切照舊,懶癌患者或者閱讀理解不過關的胖友闊以直接下載最終程式碼

有關UIStackView的使用就到這裡,關於使用UIStackView做高階動畫是稍稍有點複雜的,以後有空還是需要專門開一篇來做介紹。

相關文章