SwiftUI ZStack overlay background 詳解與區別

設計 App 畫面時,除了控制元件的上下左右位置,控制元件的階層也很重要,因為它將決定 A 元件會覆蓋元件 B 還是被 B 覆蓋,影響元件是否會被別人檔到。

在 SwiftUI 裡主要有 ZStack,overlay & background 三種技術可以調整階層,接下來讓我們一一介紹吧。

  • 將元件一層層疊上的 ZStack。
  • 將別人疊在自己身上的 overlay。
  • 將別人壓在自己底下的 background。

將元件一層層疊上的 ZStack

ZStack 跟其它 stack 元件一樣,可以在 { } 裡加入它要包含排列的元件。不同於水平排列的 HStack & 垂直排列的 VStack,它會將元件一層層疊上。

就像疊疊樂,{ } 裡愈後面產生的元件將疊在之前的元件身上,因此以下程式會先加入 Image,然後再疊上 Text,變成 Text 覆蓋 Image。

struct ContentView: View {
    var body: some View {
        ZStack {
            Image(.peter)
                .resizable()
                .scaledToFit()
            Text("愛瘋一切為蘋果的彼得潘")
        }
    }
}
 

ZStack 控制對齊的 alignment

ZStack 排列時預設會將元件全都置中,但我們可透過它的 alignment 參數控制對齊的方式。

 

範例。

將 alignment 設為 .bottom,圖片和文字對齊底部。

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            Image(.peter)
                .resizable()
                .scaledToFit()
            Text("愛瘋一切為蘋果的彼得潘")
        }
    }
}
 

ZStack 搭配 padding & offset 調整元件位置

當我們利用 ZStack 堆疊元件時,也常結合 padding & offset 調整元件位置和元件間的間距。

範例。

利用 padding 讓 Image & Text 之間不重疊,利用 offset 將 Text 往右偏移。

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            Image(.peter)
                .resizable()
                .scaledToFit()
                .padding(.bottom, 30)
            Text("愛瘋一切為蘋果的彼得潘")
                .offset(x: 50)
        }
    }
}
 

將別人疊在自己身上的 overlay

我們可以利用 overlay 將元件疊在另一個元件上,比方以下例子從 Image 呼叫 overlay,傳入 Text,因此 Text 會疊在 Image 身上。

struct ContentView: View {
    var body: some View {
        Image(.peter)
            .resizable()
            .scaledToFit()
            .overlay {
                Text("愛瘋一切為蘋果的彼得潘")
            }
    }
}
 

同樣的,overlay 也是預設置中,但我們可透過 alignment 參數控制對齊的方式。

範例。

圖片和文字對齊底部。

struct ContentView: View {
    var body: some View {
        ZStack(alignment: .bottom) {
            Image(.peter)
                .resizable()
                .scaledToFit()
                .overlay(alignment: .bottom) {
                    Text("愛瘋一切為蘋果的彼得潘")
                }
        }
    }
}
 

我們也可以結合 padding & offset 改變元件的位置。

struct ContentView: View {
    var body: some View {
        Image(.peter)
            .resizable()
            .scaledToFit()
            .padding(.bottom, 30)
            .overlay(alignment: .bottom) {
                Text("愛瘋一切為蘋果的彼得潘")
                    .offset(x: 50)
            }
    }
}
 

就像彼得潘可以一次背十幾臺 Macbook Pro,享受甜蜜的負荷,SwiftUI 的 view 也可以呼叫多次的 overlay,將多個 view 疊在自己身上。元件堆疊的順序跟 overlay 的順序有關,愈後面呼叫 overlay 加入的元件將疊在之前的元件上。

範例。

Image 呼叫了 2 次 overlay,先疊上 Text,再疊上月亮的 Image。

struct ContentView: View {
    var body: some View {
        Image(.peter)
            .resizable()
            .scaledToFit()
            .padding(.bottom, 30)
            .overlay(alignment: .bottom) {
                Text("愛瘋一切為蘋果的彼得潘")
                    .offset(x: 50, y: 0)
            }
            .overlay(alignment: .topTrailing) {
                Image(systemName: "moon.fill")
                    .resizable()
                    .frame(width: 100, height: 100)
            }
    }
}

因此階層順序如下,彼得潘在最底下支撐著文字跟奇妙仙子。

 

將別人壓在自己底下的 background

overlay 可以貼心地將別人加在自己身上,但如果喜歡欺負別人,我們也可以利用 background 將別人壓在自己底下。

我們可以利用 background 將元件放在另一個元件下,比方以下例子從 Image peter 呼叫 background,傳入 Circle,因此圓形會被可憐地壓在 peter 底下。

struct ContentView: View {
    var body: some View {
        Image(.peter)
            .resizable()
            .scaledToFit()
            .overlay(alignment: .bottom) {
                Text("愛瘋一切為蘋果的彼得潘")
            }
            .background {
                Circle()
            }
    }
}
 

同樣的,background 也是預設置中,但我們可透過 alignment 參數控制對齊,搭配 padding & offset 調整元件的位置。

struct ContentView: View {
    var body: some View {
        Image(.peter)
            .resizable()
            .scaledToFit()
            .overlay(alignment: .bottom) {
                Text("愛瘋一切為蘋果的彼得潘")
            }
            .background(alignment: .top) {
                Circle()
                    .offset(x: -30)
            }
    }
}
 

我們也可以呼叫多次的 background,將多個 view 疊在自己底下。元件堆疊的順序跟 background 的順序有關,愈後面呼叫 background 加入的元件愈慘,將被壓在愈底下,比方以下程式最後加入的 hook 將在最底層。

struct ContentView: View {
    var body: some View {
        Image(.peter)
            .resizable()
            .scaledToFit()
            .overlay(alignment: .bottom) {
                Text("愛瘋一切為蘋果的彼得潘")
            }
            .background(alignment: .topTrailing) {
                Image(.yellowPeter)
                    .offset(x: 50, y: -30)
            }
            .background(alignment: .top) {
                Circle()
            }
    }
}
 

background 很適合拿來設定元件的背景顏色,背景圖片 & 漸層背景

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章