SwiftUI-關於@ViewBuilder & @escaping

LULU
彼得潘的 Swift iOS App 開發教室
4 min readMay 24, 2022

--

在SwiftUI框架中使用很多的註解,雖然使語法非常簡潔,但是增加了初學者的理解難度QQ

ViewBuilder是一個包含多個檢視的閉包。(直譯:A custom parameter attribute that constructs views from closures.)XD

@ViewBuilder可以在參數 closure 的 { } 裡生成多個元件

如何判斷function型別參數是否為ViewBuilder

@escaping & @ViewBuilder

有@ViewBuilder時,當closure被標記為@escaping,這個值不會在初始化(init)時就被使用(@escaping特性,它允許我們存儲閉包,以便稍後使用)。
closure 屬於 reference types,他們實際存上存在於heap中

struct GridStack<Content: View>: View {
let rows: Int
let columns: Int
let content: (Int, Int) -> Content

var body: some View {
VStack {
ForEach(0 ..< rows) { row in
HStack {
ForEach(0 ..< self.columns) { column in
self.content(row, column)
}
}
}
}
}
}

第一行 struct GridStack<Content: View>: View,是 Swift 的泛型,它的意思是“你可以提供任意類型的內容,但必須遵守 View 協議。” 在冒號之後,又加了一個View,聲明 GridStack 本身也遵守View 協議。

特別注意一下 let content 這行它定義了一個closure必須接收兩個整數,並且返回某種我們可以顯示的內容。

現在我們有了一個自定義struct,我們可以用它寫一個view,像下面這樣:

struct ContentView: View {
var body: some View {
GridStack(rows: 5, columns: 5) { row, col in
Text("R\(row) C\(col)")
}
}
}

GridStack可以接收各種型別,只要它們遵守View協議。因此,可以創建自己的stack 。

GridStack(rows: 5, columns: 5) { row, col in
HStack {
Image(systemName: "\(row * 5+ col).circle")
Text("R\(row) C\(col)")
}
}

我們還可以用SwiftUI 的一個特性,叫view builder,它允許我們傳入多個view,讓view builder 為我們創建stack 。

為了使用@view builder ,需要給GridStack 初始化,因此用SwiftUI 的@view builder 系統來標記 content closure

init(rows: Int, columns: Int, @ViewBuilder content: @escaping (Int, Int) -> Content) {
self.rows = rows
self.columns = columns
self.content = content
}

有@ViewBuilder時,當closure被標記為@escaping,這個值不會在初始化(init)時就被使用(@escaping特性,它允許我們存儲閉包,以便稍後使用)。

--

--

LULU
彼得潘的 Swift iOS App 開發教室

Hi👋 I’m iOS developer, I hope I can grow with you guys ☺️ Let’s learn more together.