使用@ViewBuilder 创建支持多个 children 的视图
Using @ViewBuilder to create Views which support multiple children
SwiftUI 中的某些视图,如 VStack 和 HStack 支持具有多个视图,如 children,如下所示:
VStack {
Text("hello")
Text("world")
}
据我所知,他们使用 ViewBuilder to make this possible as explained 。
我们如何使用@ViewBuilder 创建我们自己的支持多个 children 的视图?例如,假设我想创建一个接受任意 children 的 Layout
视图——像这样:
struct Layout : View {
let content: Some View
var body : some View {
VStack {
Text("This is a layout")
content()
}
}
}
知道如何在 SwiftUI 中实现这种模式吗?
这是一个什么都不做的示例视图,只是为了演示如何使用 @ViewBuilder
。
struct Passthrough<Content>: View where Content: View {
let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
content()
}
}
用法:
Passthrough {
Text("one")
Text("two")
Text("three")
}
使用 VStack
的声明,我们需要使用 @ViewBuilder
作为我们的内容参数。它是一个闭包,但它 不应该 是 @escaping 如果我们只需要来自它的数据,那么存储闭包是不好的。我从 Apple 声明中假设。
另外我认为 @inlinable
很重要,因为:
The @inlinable attribute exports the body of a function as part of a
module's interface, making it available to the optimizer when
referenced from other modules.
More info here
struct Layout <Content> : View where Content : View {
var content: Content
@inlinable public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body : some View {
VStack {
Text("This is a layout")
self.content
}
}
}
使用方法:
Layout {
Text("1")
VStack {
Text("1")
Text("2")
}
}
更新:
正如 Matteo Pacini 指出的关于 @escaping
的误导性信息。
我们需要使用 @escaping
获得 DynamicViewContent
观看次数。
@escaping
用于接受集合(数组、范围等)的视图结构的 Apple 视图结构。因为 ForEach
实现了 DynamicViewContent
- 一种从底层数据集合生成视图的视图。 List
在其初始值设定项中也 ForEach
在内容
中
public init<Data, RowContent>(_ data: Data, selection: Binding<Selection>?, action: @escaping (Data.Element.IdentifiedValue) -> Void, rowContent: @escaping (Data.Element.IdentifiedValue) -> RowContent) where Content == ForEach<Data, Button<HStack<RowContent>>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable
SwiftUI 中的某些视图,如 VStack 和 HStack 支持具有多个视图,如 children,如下所示:
VStack {
Text("hello")
Text("world")
}
据我所知,他们使用 ViewBuilder to make this possible as explained
我们如何使用@ViewBuilder 创建我们自己的支持多个 children 的视图?例如,假设我想创建一个接受任意 children 的 Layout
视图——像这样:
struct Layout : View {
let content: Some View
var body : some View {
VStack {
Text("This is a layout")
content()
}
}
}
知道如何在 SwiftUI 中实现这种模式吗?
这是一个什么都不做的示例视图,只是为了演示如何使用 @ViewBuilder
。
struct Passthrough<Content>: View where Content: View {
let content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
content()
}
}
用法:
Passthrough {
Text("one")
Text("two")
Text("three")
}
使用 VStack
的声明,我们需要使用 @ViewBuilder
作为我们的内容参数。它是一个闭包,但它 不应该 是 @escaping 如果我们只需要来自它的数据,那么存储闭包是不好的。我从 Apple 声明中假设。
另外我认为 @inlinable
很重要,因为:
The @inlinable attribute exports the body of a function as part of a module's interface, making it available to the optimizer when referenced from other modules. More info here
struct Layout <Content> : View where Content : View {
var content: Content
@inlinable public init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body : some View {
VStack {
Text("This is a layout")
self.content
}
}
}
使用方法:
Layout {
Text("1")
VStack {
Text("1")
Text("2")
}
}
更新:
正如 Matteo Pacini 指出的关于 @escaping
的误导性信息。
我们需要使用 @escaping
获得 DynamicViewContent
观看次数。
@escaping
用于接受集合(数组、范围等)的视图结构的 Apple 视图结构。因为 ForEach
实现了 DynamicViewContent
- 一种从底层数据集合生成视图的视图。 List
在其初始值设定项中也 ForEach
在内容
public init<Data, RowContent>(_ data: Data, selection: Binding<Selection>?, action: @escaping (Data.Element.IdentifiedValue) -> Void, rowContent: @escaping (Data.Element.IdentifiedValue) -> RowContent) where Content == ForEach<Data, Button<HStack<RowContent>>>, Data : RandomAccessCollection, RowContent : View, Data.Element : Identifiable