@ViewBuilder 在自定义 View 中的使用

Posted 颐和园

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@ViewBuilder 在自定义 View 中的使用相关的知识,希望对你有一定的参考价值。

有时候我们要求一个 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 ,这给我们提供了相当大的灵活性。

以上是关于@ViewBuilder 在自定义 View 中的使用的主要内容,如果未能解决你的问题,请参考以下文章

@ViewBuilder 在自定义 View 中的使用

@ViewBuilder 在自定义 View 中的使用

在自定义 View 类中使用 UIImageView 的正确方法

如何在自定义views-view-fields.tpl.php中的<img src="">中打印图像字段

在 @ViewBuilder 闭包中更改 @State

@ViewBuilder 在使用其他属性初始化时抛出错误