最初教程由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 Layout。ide
在這份UIStackView
教程中,咱們將使用一個名爲「Vacation Spots」的應用程序。這個簡單的應用闊以展現度假地點的一些基礎信息。 不要方方髒髒的就開始動手,由於有幾個問題須要咱們先用UIStackView
來處理下,並且比單獨使用自動佈局要簡單得多。首先下載這個UIStackView教程的入門項目。打開項目並在iPhone模擬器上運行。你會看到一份度假地點清單。 工具
點擊London那一欄,進入倫敦的信息視圖。乍一看,好像還不錯,但有幾個問題。佈局
既然咱們已經羅列好了改進工做,那就動手開始吧!!!動畫
打開Main.storyboard。第一次這樣作時,會要求您選擇初始設備視圖。這個視圖在運行時沒有效果,它針對不一樣的設備調整大小,也只是讓故事板的使用變得更加容易。iPhone 7或者8就好了。 ui
這些標籤和按鈕的各類背景色,運行時會被清除。在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 Proportionally,spacing值改成10。
如今,在iPhone SE模擬器上再跑一次,此次必須棒棒噠。
咋樣,第一次上手stack view
484真香,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,左擊Stack選Unembed便可撤銷。
或者選中控件從菜單Editor \ Unembed撤銷也行。
如今咱們來建立垂直方式的堆棧視圖,選中WHY VISIT和**<whyVisitLabel>**兩個文本控件。
Xcode會根據控件的分佈排列來確實方向,就好比如今這樣,直接生成的就是垂直分佈的堆棧視圖。
如今咱們來肯定約束,只須要把這部分的上左右約束都設置爲0,只不過底部約束的對象是相對WEATHER控件,間距是20,一看即懂。
設置完後默認對齊是左對齊,以下圖所示:
對齊屬性肯定堆棧視圖如何垂直於其軸佈局。對於垂直堆棧視圖,能夠設置的對齊方式爲:
水平堆棧視圖對齊屬性的值略有不一樣:
水平佈局的對齊方式分別爲:
你們闊以選中剛纔設置好的垂直堆棧視圖,調整下對齊屬性看下變化就淺顯易懂了。 填充·Fill:
跑起來看一下佈局妥當冇問題。
這部分轉換和前面一節沒啥區別,直接操做關鍵點便可。
Top: 20, Leading: 0, Trailing: 0, Bottom: 20
複製代碼
設置完之後大概就長這樣:
因爲須要隱藏天氣,因此這部分是比較難搞的。
咱們先把這部分的全部元素都壓入堆棧視圖。先選中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
作高級動畫是稍稍有點複雜的,之後有空仍是須要專門開一篇來作介紹。