@ViewBuilder 在自定义 View 中的使用【转】

55 阅读2分钟

有时候我们要求一个 View 要有比较高的灵活性,它的一部分视图的内容需要灵活指定。比如这样的视图,它仅仅提供了一个“灰色背景”,中间的部分则可以由 View 的使用者自己定义:

那么我们可以考虑用 @ViewBuilder。

首先定义一个 SwiftUI View:

struct DialogView<T>: View where T: View{
    private let content: T
    var body: some View {
        ZStack {
            Rectangle()
                .fill(Color.black.opacity(0.6))
                .edgesIgnoringSafeArea(.all)
						VStack{
                content
            }
            .frame(width: 270)
            .background(Color(red: 0xd6/255.0, green: 0xd6/255.0, blue: 0xd6/255.0))
        .cornerRadius(14)
        }
    }

    init(@ViewBuilder content: () -> T) {
        self.content = content()
    }
}

在类名后面有一个范型 T ,用来代表 content 属性的类型。这个 content 属性就是代表了用户需要灵活定义的那部分视图 UI。我们无法在此时知道它的确切类型,因为它完全由调用者制定,可能是任意类型的 View,我们只知道它是一种 View,但无法具体知道是什么View,是一个 Text 还是 Image 还是多个 Text+Image 的组合。所以范型约束是: where T: View。

你可能想说,不可以直接使用 View 来定义 content 吗?不可以,因为 View 是一个协议,而非具体类型。

这样,我们就可以把 content 的类型定义为 T 了。

在 body 块中(其实 body 块也是一种 ViewBuilder),我们使用 content 替代了部分 UI 内容。然后在 init 方法中,通过 @ViewBuilder content 参数让调用者指定这部分 UI 的内容。你可以看到,这个参数实际上是一个 block,它没有参数,但返回的类型为 T。也就是说 Swift 通过 content 入参来推断出 T 的真正类型。

比如用户在 content 参数中传入一个 Text, 那么 T 就是 Text 类型。当然 ViewBuilder 有一个特别的地方,就是它的返回值可以有多个,因此你可以在其中构建 10 个以内(数量有限制)的不同类型 View,但 T 的类型仍然能被正确推断出来:

DialogView(content: {
                Spacer().frame(height: 16)
                Image(systemName: "exclamationmark.circle")
                    .foregroundColor(.red)
                Spacer().frame(height: 2)
                Text("Hint").font(.system(size: 17, weight: .semibold, design: .default)).foregroundColor(.red)
                Spacer().frame(height: 16)
                Divider()
                Button {
                    debugPrint("close")
                } label: {
                    Text("OK").font(.system(size: 17)).foregroundColor(Color(red: 0, green: 0x7a/255.0, blue: 0xff/255.0))
                }.padding(.vertical,11)
            })

这样,你看到的效果就如本文一开头的截图所示。如你所见,content 的内容完全就如同你构建一个 SwiftUI View 的 body ,这给我们提供了相当大的灵活性。

本文转自 kmyhy.blog.csdn.net/article/det…,如有侵权,请联系删除。