SwiftUI也是可以自定義容器的殷绍,我們將創(chuàng)建一個名為 GridStack 的新容器扳抽,它可以讓我們在網(wǎng)格內(nèi)創(chuàng)建任意數(shù)量的視圖。
//<Content:View>意味著內(nèi)容必須是符合View協(xié)議的控件贸呢,而GridView本身也必須符合View協(xié)議
struct GridStack <Content: View>: View {
let rows: Int, columns: Int
//定義了一個閉包拢军,返回需要展示的內(nèi)容
let content: (Int, Int) -> Content
var body: some View {
VStack {
ForEach(0..<rows, id: \.self) { row in
HStack {
ForEach(0..<columns, id: \.self) {column in
self.content(row, column)
}
}
}
}
}
}
當(dāng)循環(huán)遍歷范圍時,只有當(dāng)我們確定范圍內(nèi)的值不會隨時間變化時固蛾,SwiftUI 才能直接使用范圍。這里我們使用ForEach 0..<rows和0..<columns艾凯,這兩個值都可以隨時間變化——例如,我們可能會添加更多行或列蜡感。在這種情況下,我們需要添加第二個參數(shù)ForEach郑兴,id: .self以告訴SwiftUI它如何能夠識別循環(huán)中的每個視圖贝乎。
此時,我們的自定義容器就可以使用了:
struct ContentView: View {
var body: some View {
GridStack(rows: 4, columns: 4) { row, col in
HStack {
Image(systemName: "\(row * 4 + col).circle")
Text("R\(row) C\(col)")
}
}
}
}
為了更靈活的使用自定義容器览效,我們可以使用@ViewBuilder-視圖構(gòu)建器,它允許我們發(fā)送多個視圖并讓它為我們形成一個隱式堆棧禁筏。
我們?yōu)镚ridStack創(chuàng)建一個自定義初始化器,以便我們可以將content閉包標(biāo)記為使用 SwiftUI 的視圖構(gòu)建器系統(tǒng):
init(rows: Int, columns: Int, @ViewBuilder content: @escaping (Int, Int) -> Content) {
self.rows = rows
self.columns = columns
self.content = content
}
有了它篱昔,SwiftUI 現(xiàn)在將自動在我們的單元格閉包中創(chuàng)建一個 隱式水平堆棧:
GridStack(rows: 4, columns: 4) { row, col in
Image(systemName: "\(row * 4 + col).circle")
Text("R\(row) C\(col)")
}