什么是@ViewBuilder?
从字面意思去理解 ViewBuilder 就是视图构建
,其主要使用场景就是构建视图。
在Apple的官方文档中有这样一句话
allowing those closures to provide multiple child views
允许闭包中提供多个子视图
就是对@ViewBuilder的最好的解释。
不使用@ViewBuilder时你只能传递一个View在闭包里,使用@ViewBuilder你可以传递多个View到闭包里面
结合ViewBuilder和便利构造函数使代码更优美。
可以在项目中通过ViewBuilder注解和便利构造函数把许多具体相同特点的View封装起来,并且分离逻辑代码和视图,提升代码的可复用性,并增强可读性。
看了下面的例子你可能就会对@ViewBuilder结合便利构造器的使用有一个更好的理解。
如果我们想要设置一个Text的背景为红色,圆角为5。我们可能这样去写
Text("Liaoworking")
.background(Color.red)
.cornerRadius(5)
后来产品加需求了: 图片也是红色的背景,圆角为5:
Image("Liaoworking")
.background(Color.red)
.cornerRadius(5)
再后来产品又加需求:一些自定义视图也是红色的背景,圆角为5:
这里假设我们的自定义视图类为MyView
MyView()
.background(Color.red)
.cornerRadius(5)
聪明的你肯定想到了用一个View的extension来统一处理。
extension View {
func addRedBGWithRoundCorner() -> some View {
self
.background(Color.red)
.cornerRadius(5)
}
}
//调用:
Text("Liaoworking").addRedBGWithRoundCorner()
这样做的确可以达到相同的效果,而且代码也会简洁不少。
这个时候你还可以用@ViewBuilder
注解来创建你的自定义视图达到相同的效果:
struct RedBackgroundAndCornerView<Content: View>: View {
let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
content
.background(Color.red)
.cornerRadius(5)
}
}
使用方法如下:
RedBackgroundAndCornerView {
Text("liaoworking")
}
两种封装的最后效果都是一样的,你可能会觉得,View的extension封装要比@ViewBuilder 封装 好太多
。代码都少写很多。
但是突然有一天,你的产品经理决定再加一个功能,在Text("liaowokring") 右边再加一个图片。
如果使用如果不使用@ViewBuilder关键字的话 你必须要用一个HStack把两个元素包裹住才能编译通过。
RedBackgroundAndCornerView {
HStack {
Text("liaoworking")
Image("hello")
}
}
但是当你使用了@ViewBuilder 关键字 你可以不需要HStack包裹,直接写,和HStack包裹效果一样:
RedBackgroundAndCornerView {
Text("liaoworking")
Image("hello")
}
除此之外 @ViewBuilder 还有一个更好用的地方
可能你在开发中经常会遇到下面这个编译报错
Function declares an opaque return type 'some View', but the return statements in its body do not have matching underlying types
就是当你不同的条件下返回的视图不同时编译器不允许你有这样的写法。
相信每一位SwiftUI的初学者都遇到过这样的报错。
这个时候就可以用神器 @ViewBuilder 去标注你的content属性
, 可以顺利的编译并且按照你所设想的方式运行。
注:@ViewBuilder 不仅可以标注计算型属性,还可以标注func
用法同理。
over.