UIStackView上手教程

原文:UIStackView Tutorial: Introducing Stack Viewsswift

最初教程由Jawwad Ahmad原創。Kevin Colligan更新支持iOS 十一、Xcode 9和Swift 4。bash

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

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

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

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

教程開始

在這份UIStackView教程中,咱們將使用一個名爲「Vacation Spots」的應用程序。這個簡單的應用闊以展現度假地點的一些基礎信息。 不要方方髒髒的就開始動手,由於有幾個問題須要咱們先用UIStackView來處理下,並且比單獨使用自動佈局要簡單得多。首先下載這個UIStackView教程的入門項目。打開項目並在iPhone模擬器上運行。你會看到一份度假地點清單。 工具

點擊London那一欄,進入倫敦的信息視圖。乍一看,好像還不錯,但有幾個問題。佈局

  • 看看視圖底部的一排按鈕。他們目前的位置是固定的,因此他們不適應屏幕寬度。不信按Command - left將模擬器橫向來看看。
  • 點擊WEATHER旁邊的Hide按鈕。它成功地隱藏了文本,可是它沒有從新定位它下面的部分,留下一塊空白。
  • 能夠改進這些部分的展現順序。若是what to see部分正好位於why visit部分以後,而不是在二者之間有weather部分,這將會更合乎邏輯。
  • 在橫屏模式下,按鈕的底部離視圖的底部邊緣太近了一點。若是能減小元素之間的間距,那就更好看。

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

打開Main.storyboard。第一次這樣作時,會要求您選擇初始設備視圖。這個視圖在運行時沒有效果,它針對不一樣的設備調整大小,也只是讓故事板的使用變得更加容易。iPhone 7或者8就好了。 ui

你闊以隨時點擊故事板的操做區域的正下方,選擇 View As: iPhone 7 ,或者隨便改變也行。
如今打開
Spot Info View Controller
看看,這東一塊西一坨的顏色是什麼鬼?

這些標籤和按鈕的各類背景色,運行時會被清除。在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選中底部三個按鈕。

點擊右下角Show Document Outlin

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

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

按鈕將嵌入到新的堆棧視圖中:

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

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

點擊選中Submit Rating按鈕能夠看到它不在包含任何約束。

也闊以經過**Size inspector (⌥⌘5)**來查看控件約束狀況:

接下來咱們須要爲stack view添加約束控制,若是整個頁面的控件太多致使很差選中某個控件,直接從左側的控件列表就好。

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

最後經過右下角的Auto Layout toolbar添加約束便可。

保持Constrain to margins選中,而後添加以下約束。

Top: 20, Leading: 0, Trailing: 0, Bottom: 0
複製代碼

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

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

決定stack view內部控件的分佈屬性爲distribution。目前,它被設置爲Fill,這意味着被包含的控件將沿着其軸徹底填充。爲了實現這一點,stack view將只拉伸其中一個視圖來填充額外的空間;具體來講,它會拉伸content hugging優先級最低的視圖,或者若是全部控件優先級相同,它拉伸第一個視圖。

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

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

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

如今,在iPhone SE模擬器上再跑一次,此次必須棒棒噠。

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

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

若是隻是偶爾這麼作一次其實還好,若是作多了,小夥子身體可吃不消啊。特別是動態添加視圖這種。好比隱藏例子中的WEATHER這種。

如今咱們只是簡單的設置間距值,若是你想在某個視圖中設置特別的間距,在iOS11裏提供的新的Api: setCustomSpacing:afterView

沙場老司機

通過上面的演練,下面咱們就能很輕鬆的把SpotInfoViewController裏須要的結構轉換成stack view

評級部分

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

接着仍是一樣的點擊Stack按鈕將其嵌入到stack view裏。

此次咱們只須要添加三個約束便可:

Top: 20, Leading: 0, Bottom: 20
複製代碼

spacing值這是爲8

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

若是肯定本身的約束是正確的,由於Xcode某些版本的bug引發的視圖錯位,直接用右下角的Refresh Layout按鈕矯正便可。

如今看起來就正常了。

還原視圖

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

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

試試第一個垂直方式

如今咱們來建立垂直方式的堆棧視圖,選中WHY VISIT和**<whyVisitLabel>**兩個文本控件。

Xcode會根據控件的分佈排列來確實方向,就好比如今這樣,直接生成的就是垂直分佈的堆棧視圖。

如今咱們來肯定約束,只須要把這部分的上左右約束都設置爲0,只不過底部約束的對象是相對WEATHER控件,間距是20,一看即懂。

設置完後默認對齊是左對齊,以下圖所示:

對齊屬性

對齊屬性肯定堆棧視圖如何垂直於其軸佈局。對於垂直堆棧視圖,能夠設置的對齊方式爲:

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

水平堆棧視圖對齊屬性的值略有不一樣:

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

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

你們闊以選中剛纔設置好的垂直堆棧視圖,調整下對齊屬性看下變化就淺顯易懂了。 填充·Fill:

靠左對齊·Leading:
居中對齊·Center:
靠右對齊·Trailing:

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

轉換「what to see」部分

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

  • 首先選中WHAT TO SEE和**<whatToSeeLabel>**兩個文本元素。
  • 其次壓入堆棧視圖。
  • 對齊方式選中填充·Fill。
  • 最後設置好以下約束便可。
Top: 20, Leading: 0, Trailing: 0, Bottom: 20
複製代碼

設置完之後大概就長這樣:

轉換「weather」部分

因爲須要隱藏天氣,因此這部分是比較難搞的。

咱們先把這部分的全部元素都壓入堆棧視圖。先選中WEATHER文本欄和Hide按鈕,壓入水平堆棧視圖,而後在按住Command選中下面的**<weatherInfoLabel>**文本欄部分,將水平堆棧視圖和這部分一塊兒壓入垂直堆棧視圖。

其實能夠發現,水平的堆棧視圖被Hide按鈕給頂開了,若是以爲不喜歡,闊以選中底部對齊的方式來看看效果。

也仍是不太滿意,那根據個人經驗,要不就是修改水平堆棧視圖內UI元素的約束優先級,要不就是把Hide按鈕給拆出去,單獨處理約束。爲了容易理解咱們仍是單獨處理。

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

將其壓入垂直堆棧視圖:

而後設置好以下約束:

Top: 20, Leading: 0, Trailing: 0, Bottom: 20
複製代碼

對齊方式爲填充:

由於Hide按鈕被拆出去,因此咱們須要對其添加約束以保證按鈕位置的正確性。由於須要設置約束的相對控件爲WEATHER文本欄,因此咱們還得再改造改造。 直接在控件列表欄選中WEATHER或使用組合拳Control-Shift-click

壓入堆棧視圖:

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

運行看看是啥狀況:

我頂你個肺,啥狀況,按鈕跑偏了?其實是咱們拆出Hide按鈕以後忘記給設置約束。 按住Control選中Hide按鈕拖動指向到WEATHER文本欄添加約束:

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

再從新跑一下,這回就必須穩當了。

堆棧化

在左側控件列表裏選中咱們以前全部作個堆棧化的控件:

所有壓入堆棧:

而後給最外層堆棧視圖添加約束,確保勾選上Constrain to margins,四邊邊距約束爲0便可。 而後間隙·Spacing設置爲20對齊方式·Alignment設置爲填充·Fill

再次運行仍是會有剛纔那個屌問題。

只要記住若是有外設相對控件的約束,只要堆棧化,約束就會被幹掉,只能再次添加了:

完善層級

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

若是在Storyboard裏直接去拖動,極可能會由於選錯控件元素而致使打亂結構。

根據屏幕大小配置間隙

因爲在橫屏的狀況下,垂直方向上的空間比較珍貴,因此針對橫屏,把間隙改成10比較穩妥。 找到間隙·Spacing的左側的**+**號按鈕:

選擇Any Width > Compact Height,而後添加·Add Variation

wAny hC欄添加值爲10便可:

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

動畫

當前的隱藏和呈現動畫效果看起來有木有點生硬,感受怪怪的。咱們仍是添加點動畫讓細節看起來比較絲滑爲妙。 打開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作高級動畫是稍稍有點複雜的,之後有空仍是須要專門開一篇來作介紹。

相關文章
相關標籤/搜索