利用 SwiftUI 的 Spacer & padding 調整元件位置

預設置中的 SwiftUI

當我們利用 SwiftUI 設計 App 畫面時,它預設將置中顯示元件,比方以下例子。

struct ContentView: View {
var body: some View {
VStack {
Image(.peter)
Text("AII children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. ")
}
.border(.black)
}
}

利用 Spacer 長出看不見的空間,讓元件靠左,靠右,靠上或靠下

不過很多畫面的排版都是從上面 & 左邊開始呈現內容,有方法調整嗎 ?

當然可以,由於 SwiftUI 大量運用 stack 排版,所以我們可以在 stack 裡搭配 Spacer,讓元件靠左,靠右,靠上或靠下。

struct ContentView: View {
var body: some View {
VStack {
Image(.peter)
Text("AII children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. ")
Spacer()
}
.border(.black)
}
}

當我們在 VStack 裡加入 Spacer 時,它將判斷 VStack 可使用的空間,延著 Y 軸長出一塊看不見的空間。以剛剛的程式為例,Spacer 是 VStack 的最後一個元件,因此它會佔據下方的空間,將 Image & Text 往上推。由於 body 裡只有 VStack,所以此時 Spacer 將判斷 VStack 可使用整個 iPhone 螢幕的高度,於是如下圖所示,VStack 長成接近 iPhone 螢幕的高度,實現 Image & Text 從上方開始排列的效果。

並非加了 Spacer 就會讓 stack 變成整個 iPhone 的大小,比方當我們以 frame 指定 VStack 的高度為 500 時,Spacer 將知道 VStack 的高度是 500,所以它只會將 Imaeg & Text 往上推,自己佔據剩下的空間。

struct ContentView: View {
var body: some View {
VStack {
Image(.peter)
Text("AII children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. ")
Spacer()
}
.frame(height: 500)
.border(.black)

}
}

Spacer 擺放在不同的位置將產生不同的效果,比方當 Spacer 放在 Image & Text 中間時,Image & Text 將被遠遠的分隔開來,變成圖片靠上,文字靠下。

struct ContentView: View {
var body: some View {
VStack {
Image(.peter)
Spacer()
Text("AII children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. ")
}
.border(.black)
}
}

當 Spacer 成為 VStack 的第一個元件時,變成 Image & Text 置底。

struct ContentView: View {
var body: some View {
VStack {
Spacer()
Image(.peter)
Text("AII children, except one, grow up. They soon know that they will grow up, and the way Wendy knew was this. ")
}
.border(.black)
}
}

當 Spacer 加在 HStack 時,將變成延著 X 軸長出一塊看不見的空間。如下圖所示,Spacer 將分隔 Image & Text,並讓 HStack 佔滿 iPhone 螢幕的寬度。

struct ContentView: View {
var body: some View {
HStack {
Image(.peter)
Spacer()
Text("Peter")
}
.border(.black)
}
}

利用 Spacer 設定間距

我們也可以利用 Spacer 設定間距,比方以下例子設定 Spacer 的高度為 50,因此圖片和文字的間距是 50。

struct ContentView: View {
var body: some View {
VStack {
Image(.peter)
Spacer()
.frame(height: 50)
Text("Peter")
}
.border(.black)
}
}

ps: 雖然 Spacer 可以設定間距,不過我們更常用 stack 的參數 spacing 或是等下要介紹的 padding 設定間距。

利用 padding 設定元件內容和元件邊界的間距

padding 可以在元件的上下左右置入邊距,保留一點空白空間。

沒有 padding 時,Text 的大小就是文字 Peter 的大小,因此文字會完全靠邊。

struct ContentView: View {
var body: some View {
Text("Peter")
.background {
Color.yellow
}
}
}

加入 padding 後,Text 的內容和 Text 的邊界有了間距,因此 Peter 跟邊邊多出一些空白。

struct ContentView: View {
var body: some View {
Text("Peter")
.padding()
.background {
Color.yellow
}
}
}

以剛剛加了 Spacer 的 HStack 為例,我們希望圖片和文字不要那麼靠近邊界,此時 padding 也可以派上用場。

struct ContentView: View {
var body: some View {
HStack {
Image(.peter)
Spacer()
Text("Peter")
}
.padding()
.border(.black)
}
}

如下圖所示,此時 HStack 的上下左右都多出一塊預設的間距。

padding 還可以做很多變化,比方以下例子。

  • 指定間距大小 40。
.padding(40)
  • 分別指定左右的間距。
.padding(.leading, 10)
.padding(.trailing, 30)
  • 加入水平間距。
.padding(.horizontal)
  • 分別指定上下左右的間距。
.padding(EdgeInsets(top: 10, leading: 15, bottom: 5, trailing: 15))
  • 指定某幾個地方的 padding。

比方指定上面跟左邊的 padding 為 10。

.padding([.top, .leading], 10)

剛剛的例子都是用 padding 設定邊距,以下例子則是用 padding 設定元件間的間距。

struct ContentView: View {
var body: some View {
HStack(spacing: 0) {
Image(.peter)
Text("Peter")
.padding(.leading, 10)
}
}
}

利用 padding 讓 button 的內容和邊框保持安全距離

當我們在 button 上添加 border 後將產生有點可怕的結果。

struct ContentView: View {
var body: some View {
Button("IG") {
}
.font(.largeTitle)
.border(.blue, width: 3)
}
}

如下圖所示,文字跟邊框整個黏在一起,跟談戀愛一樣,有時太黏也不是好事。

還好,我們有 padding,它可以為我們長出一些安全距離。

struct ContentView: View {
var body: some View {
Button("IG") {
}
.font(.largeTitle)
.padding()
.border(.blue, width: 3)
}
}

利用多個 Spacer 實現等間距效果

以下的 HStack 有三個 button,我們在 button 之間加入 Spacer 讓 button 間有一樣的間距。

struct ContentView: View {
var body: some View {
HStack {
Button("FB") {
}
.padding()
.border(.blue, width: 3)

Spacer()

Button("IG") {
}
.padding()
.border(.blue, width: 3)

Spacer()

Button("LINE") {
}
.padding()
.border(.blue, width: 3)
}
.padding()
}
}

利用 padding & offset 讓 HStack 或 VStack 裡的元件重疊

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com