SwiftUI-自定义容器

2021-07-17  本文已影响0人  rayChow

SwiftUI也是可以自定义容器的,我们将创建一个名为 GridStack 的新容器,它可以让我们在网格内创建任意数量的视图。

//<Content:View>意味着内容必须是符合View协议的控件,而GridView本身也必须符合View协议
struct GridStack <Content: View>: View {
    let rows: Int, columns: Int
    //定义了一个闭包,返回需要展示的内容
    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)
                    }
                }
            }
        }
    }
}

当循环遍历范围时,只有当我们确定范围内的值不会随时间变化时,SwiftUI 才能直接使用范围。这里我们使用ForEach 0..<rows和0..<columns,这两个值都可以随时间变化——例如,我们可能会添加更多行或列。在这种情况下,我们需要添加第二个参数ForEach,id: .self以告诉SwiftUI它如何能够识别循环中的每个视图。
此时,我们的自定义容器就可以使用了:

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-视图构建器,它允许我们发送多个视图并让它为我们形成一个隐式堆栈。
我们为GridStack创建一个自定义初始化器,以便我们可以将content闭包标记为使用 SwiftUI 的视图构建器系统:

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

有了它,SwiftUI 现在将自动在我们的单元格闭包中创建一个 隐式水平堆栈:
GridStack(rows: 4, columns: 4) { row, col in
    Image(systemName: "\(row * 4 + col).circle")
    Text("R\(row) C\(col)")
}
上一篇下一篇

猜你喜欢

热点阅读