本篇原文(標題:How To Evenly Space Views in SwiftUI )刊登於作者 Medium,由 Anupam Chugh 所著,並授權翻譯及轉載。
我早前花了幾個月開發 UIKit 專案,最近終於回到 SwiftUI。奇怪的是,我竟然花了一些時間來編寫最基本的原型:如何在我的圖像過濾 SwiftUI App 中,平均地佈局兩個圖像呢?
我試過在 HStack 中的兩個 Images 上,設置 resizable() 和 AspectRatio() 修飾符,但是沒有成功。實際上,由於實際的圖像資源太大,因此其中一個圖像佔據了整個螢幕。當然,我們還是可以寫死 (hardcode) 寬度和高度,但這不是對所有螢幕尺寸和方向都有效。
我暫停了 SwiftUI 開發一段時間,現在很高興能跟大家分享不同的技巧,來在 SwiftUI 中佈局視圖。讓我們開始吧!
利用 Spacers、Stack Spacing 和 Alignment
顧名思義,Spacers 會佔用可用的空間,而它們填充空間的方式,就視乎我們把 Spacers 包裝在 HStack 還是 VStack 中。
看看以下例子:
VStack {
Image(systemName: "shield.fill")
Spacer()
}
如你所見,Spacer 垂直地佔用了可用的空間。第一個 Spacer 將 Image 推到螢幕頂部。如果想讓所有視圖等距分佈,就要在每個視圖之間添加一個 Spacer()。
我們也可以在 Stacks 中添加間距,並對齊視圖。我們更可以搭配使用 Stack 間距 (spacing) 和 Spacer,靈活地排列視圖。
以下面的程式碼為例,我們利用一個 Spacer 來把 HStack 對齊螢幕左側。另外,我們還使用了 Stack 間距和對齊方式 (alignment),來排列 SwiftUI 的 Text:

現在,如果我們在兩個 Text 視圖之間放置另一個 Spacer(),效果會是怎樣呢?視圖會佔據整個螢幕,還是只會佔據 HStack 的可用高度?
答案是,由於我們尚未為 HStack 指定高度,因此視圖會佔據整個螢幕。為了確保 VStack 不會超出 HStack 的空間,我們可以設置一個固定的 frame 高度。
利用 Shapes
在上面的部分,我們了解到 SwiftUI 中的 Texts 和 Images 如何佔據空間,但另一方面,Shapes 可以讓我們覆蓋更多的空間。
因此,我們可以把視圖放在 Shape 中,以填滿 Stack 的可用空間,並平均地佈局視圖。
看看以下例子:

Shape 是平均填滿空間的好方法,你也可以利用 Shape 快速創建類似單元格 (cell) 的客製化視圖。
我們不會使用 overlay 視圖修飾符來放置子視圖,而是使用 ZStack。
利用 Frame Modifier
通常,我們會創建寬度或高度相等的視圖。在這種情況下,我們可以使用 frame 修飾符,把 maxWidth 或 maxHeight 設置成 .infinity,以強制將寬度和高度設置為最大可用空間。
以下是 frame 佈局修飾符的使用範例:

請注意,如果我們在 frame 前設置 background 修飾符,會導致 VStack 剩餘一些空間。因為 background 修飾符是應用於 Frame 的視圖,而不是整個 Stack。因此,正確排列視圖修飾符非常重要。
利用 Grids
雖然以上三種方法都足夠讓我們任意佈局視圖,但在視圖太多時,使用 Spacer 或 Frame 修飾符可能會產生一些模組化程式碼 (boilerplate code)。
幸好,在這種情況下,我們可以利用 iOS 14 推出的 SwiftUI LazyVGrid 和 LazyHGrid。

在上面的程式碼中,我們創建了水平 Grid 物件,所以 SwiftUI Group 包裝的每個 Text 的寬度都會相同。
結論
在這篇文章中,我們說明了四種方法去管理視圖之間的空間。在組成視圖時,我們經常需要平均地佈局視圖。現在,我們已經學會了在甚麼情況下該應用這些技術!
本篇文章到此為止,謝謝你的閱讀。