📦ViewBuilder
From Xcode 12, both switch and if let are supported in the ViewBuilder!
ViewBuilder as a Parameter
SwiftUI ⟩ ViewBuilder
Using ViewBuilder ⭐️
共有四個步驟:
// ⭐️ Step 1: Create a View struct like this:
// ⭐️ Note : `Content` conforms to `View`
struct MyContainerView<Content: View>: View {
...
}// ⭐️ Step 2: Add `content` property and initializer
struct MyContainerView<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
}// ⭐️ Step 3: Implementing `View` protocol requirement
struct MyContainerView<Content: View>: View {
let content: Content
var body: some View {
// use `content` somewhere in your code
content
// ... (other customizations)
}
}// ⭐️ Step 4: Use `MyContainerView` just like a `VStack` or `HStack`
struct ContentView: View {
var body: some View {
MyContainerView {
// content here ...
}
}
}// ⚠️ 模板使用注意事項:
// 1. 記得更改 `MyContainerView` 名稱。
// 2. 只要填寫步驟 ⭐️ 4,其他步驟不需更動。
struct MyContainerView<Content: View>: View {
// ⭐️ 1. `content` 屬性
// `MyContainerView` 的原始內容,由 .init(content:) 傳進來。
let content: Content
// ⭐️ 2. `init()`
// `content` 是一個擁有 @ViewBuilder 屬性的 closure,
// 所以可以像用 `HStack` 一樣使用 `MyContainerView`。
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
// ⭐️ 3. 遵循 `View` 協定
var body: some View {
// ⭐️ 4. 調整 `content` 成為你要的樣子。
}
}Examples
// ⭐️ generic structure
struct Card<Content> : View where Content : View {
// ⭐️ 卡片的內容,由 .init(content:) 傳進來。
// ⭐️ `Content` 的型別也是由 init(content:) 決定。
var content: Content
// init(content:)
init(@ViewBuilder content: () -> Content) { // ⭐️ @ViewBuilder
self.content = content()
}
// view body
var body: some View {
// 卡片內容
content
// 卡片風格
.padding() // 留白邊
.foregroundColor(.black)
.background(Color.white) // 白背景
.cornerRadius(8) // 截圓角
.shadow(radius: 4) // 畫陰影
}
}在 📦 Card 中:
init(@ViewBuilder content: () -> Content)content 是一個擁有 @ViewBuilder 屬性的 closure, 因此我們在使用 Card 的時候,可以像用 HStack 一樣, 使用下面的語法:
Card { ... }其中 { ... } 就是 content closure。
但這個 closure 並不是一般的 closure,它是一個 ViewBuilder, 意思就是說:這個 closure 裡面「每一行程式碼」所產生的 view都會變成 ViewBuilder 裡面的某個 buildBlock() 的「參數」,例如我們輸入:
Card {
C0
C1
}這段程式碼其實會呼叫 ViewBuilder 的: .buildBlock(C0, C1) 函數,然後產生一個新的 view 出來,而這個 view 的型別就會被自動設定成 Content。以上面的例子來說,
Content == Card<TupleView<C0, C1>>
import SwiftUI
import PlaygroundSupport
// live view
struct ContentView: View {
var body: some View {
Card { // 📦 Card
HStack {
Image(systemName: "person.circle")
Text("Hello World")
}.font(.largeTitle)
}.padding(40).background(Color.gray)
}
}
PlaygroundPage.current.setLiveView(ContentView())View Builders - NetSplit.com
Last updated
Was this helpful?