SwiftUI构建多个视图@ViewBuilder
SwiftUI构建多个视图@ViewBuilder

SwiftUI构建多个视图@ViewBuilder

@ViewBuilder 是 SwiftUI 提供的属性包装器,用来构建多个视图,并将它们组合成单个返回值。它是 SwiftUI 处理视图层级的一种方式,尤其在声明式语法中,@ViewBuilder 提供了简洁且灵活的代码组织方式。

基本用法

@ViewBuilder的作用:允许在一个作用域中写出多个视图语句,不需要显式用容器包裹(VStack、Group)。

为了理解这一点,可以用实际的代码进行展示:

private struct testSettings: View {
    func makeView() -> some View {
        Text("Hello")
        Text("World")
    }
    var body: some View {
        makeView()
    }
}

makeView方法显示两个Text视图,但是这个写法会报错:

Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type

因为Swift要求一个函数必须返回单一的值,这里实际上返回了两个Text。

当设置return时,那么实际上只能返回一个Text视图:

private struct testSettings: View {
    func makeView() -> some View {
        Text("Hello")   // 未返回
        return Text("World")
    }
    var body: some View {
        makeView()
    }
}

因此,需要使用Group或者VStack等视图包裹返回:

private struct testSettings: View {
    func makeView() -> some View {
        Group {
            Text("Hello")
            Text("World")
        }
    }
    var body: some View {
        makeView()
    }
}

这里返回的是Group视图,因此不需要显式的标记return关键字。

@ViewBuilder的作用是替代Group,也就是可以不使用Group、VStack等视图包裹的情况下,返回多个视图:

private struct testSettings: View {
    @ViewBuilder
    func makeView() -> some View {
        Text("Hello")
        Text("World")
    }
    var body: some View {
        makeView()
    }
}

这里就不会出现return返回单一值的报错。

这是因为 @ViewBuilder 会在编译阶段将这段代码转换为:

var body: some View {
    TupleView((Text("Hello"), Text("World")))
}

也就是说@ViewBuilder自动组装多个视图为一个整体。

工作原理

@ViewBuilder 是一个特殊的 result builder(结果构建器)。

本质上,它是一个编译器魔法结构,大概定义如下(简化):

@resultBuilder
struct ViewBuilder {
    static func buildBlock(_ components: some View...) -> some View {
        TupleView(components)
    }
}

当使用 @ViewBuilder 的作用域里写多个表达式时,编译器会自动调用 buildBlock 来合并这些视图。

@ViewBuilder 的局限性

虽然 @ViewBuilder 很强大,但它也有一些限制:

返回类型必须是 View:不能直接返回非视图类型。

嵌套层级:复杂的逻辑中可能需要用容器(如 Group)来辅助构建。

限制控制流:某些复杂控制流可能无法直接用 @ViewBuilder 表达。

使用场景

动态内容生成:根据条件分支生成不同的视图。

简化代码:避免显式地用 VStack、HStack 包裹多视图,代码更简洁。

封装视图逻辑:用于自定义容器组件,例如 SwiftUI 的 VStack 或 HStack 本质上也使用了类似的 @ViewBuilder。

注意事项

1、返回类型一致:条件语句中返回的视图类型需要一致。例如,不能在一个分支返回 Text,另一个分支返回 Image。

2、不能嵌套 @ViewBuilder:@ViewBuilder 不能直接嵌套使用。错误代码

struct ContentView: View {
    @ViewBuilder var body: some View {
        @ViewBuilder // 错误:嵌套使用会报错
        var innerView: some View {
            Text("Hello")
        }

        innerView
    }
}

报错代码为:

Underlying type for opaque result type 'some View' could not be inferred from return expression

表示无法从返回表达式中推断出不透明结果类型“some View”的底层类型。

3、@ViewBuilder 是一个“函数构建器”,只能修饰

var body: some View(SwiftUI 特殊支持)

函数参数(如 init(@ViewBuilder content: () -> Content))

计算属性(@ViewBuilder var something: some View { … })

它不能修饰普通的存储属性(let content: View)。

总结

@ViewBuilderk可以将多个视图表达式在编译器合成一个View。

它可以修饰方法、变量或者body。

有人可能疑惑,为什么View的body没有添加@ViewBuilder仍然可以工作?

private struct testSettings: View {
    var body:some View {    // 没有使用@ViewBuilder
        Text("Hello")
        Text("World")
    }
}

SwiftUI在View协议中的定义(简化版):

public protocol View {
    associatedtype Body: View
    @ViewBuilder var body: Self.Body { get }
}

body属性在协议定义时已经添加 @ViewBuilder。

所有遵循 View 协议的 struct,它的 body 都隐式带有 @ViewBuilder 行为。

扩展知识

1、@ViewBuilder修饰的函数和变量

@ViewBuilder既可以修饰函数:

@ViewBuilder func myContent() -> some View

也可以修饰变量:

@ViewBuilder var myContent: some View

两者都可以返回视图,区别在于函数可以传递参数,但是每次调用时都会创建新的视图;变量不可以传递参数,但是编译器可以缓存并优化。

@ViewBuilder
func sectionView(title: String) -> some View {
    Text(title)
    Divider()
}

@ViewBuilder
var footerView: some View {
    Text("© 2025 Fang Junyu")
}

sectionView() 可以重用、动态生成。fotterView是固定视图。

   

如果您认为这篇文章给您带来了帮助,您可以在此通过支付宝或者微信打赏网站开发者。

欢迎加入我们的 微信交流群QQ交流群,交流更多精彩内容!
微信交流群二维码 QQ交流群二维码

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注