Post

SwiftUI3:自定义容器

参考:

使用泛型做一些很强大的封装

1
2
3
4
5
6
7
8
9
struct GridStack<Content: View>: View {
    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content

    var body: some View {
        // more to come
    }
}

第一行 —— struct GridStack<Content: View>: View —— 用一个 Swift 的高级特别叫 泛型,在这里它的意思是 “你可以提供任意类型的内容,但它必须遵循 View 协议。” 在冒号之后,我们又加了一个 View ,声明 GridStack 本身也遵循View 协议。特别注意一下 let content 这行 —— 它定义了一个闭包 —— 必须接收两个整数,并且返回某种我们可以显示的内容。我们需要完成 body 属性 —— 通过组合多个 vertical 和 horizontal 的 stack 来按要求创建许多单元。我们不需要说明每个单元里有什么,因为我们可以通过合适的行号和列号来调用 content 闭包

完整Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
struct GridStack<Content: View>: View {
    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content

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

}
// 调用Demo
GridStack(rows: 4, columns: 4) { row, col in
        Text("R\(row) C\(col)")
    }

使用ViewBuilder创建, ViewBuilder会自动将多个视图组创建一个stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct GridStack2<Content: View>: View {
    let rows: Int
    let columns: Int
    let content: (Int, Int) -> Content
    
    init(rows: Int, columns: Int, @ViewBuilder content: @escaping (Int, Int) -> Content) {
        self.rows = rows
        self.columns = columns
        self.content = content
    }


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

}
// 调用Demo
GridStack2(rows: 4, columns: 4) { row, col in
            Image(systemName: "\(row * 4 + col).circle")
            Text("R\(row) C\(col)")
        }

image

This post is licensed under CC BY 4.0 by the author.