在 SwiftUI 中是否可以有一个可选的@ViewBuilder闭包?例如,假设我想开发一个自定义视图,它采用两个视图构建器闭包,如下所示:
import SwiftUI
struct TopAndBottomView<Content>: View where Content: View {
let topContent: () -> Content
let bottomContent: () -> Content
init(@ViewBuilder topContent: @escaping () -> Content, @ViewBuilder bottomContent: @escaping () -> Content) {
self.topContent = topContent
self.bottomContent = bottomContent
}
var body: some View {
VStack {
topContent()
Spacer()
bottomContent()
}
}
}
struct TopAndBottomView_Previews: PreviewProvider {
static var previews: some View {
TopAndBottomView(topContent: {
Text("TOP")
}, bottomContent: {
Text("BOTTOM")
})
}
}
Run Code Online (Sandbox Code Playgroud)
但我希望底部视图是可选的。我试过:
struct TopAndBottomView<Content>: View where Content: View {
let topContent: () -> Content
let bottomContent: (() -> Content)?
init(@ViewBuilder topContent: @escaping () -> Content, @ViewBuilder bottomContent: (() -> Content)? = nil) {
self.topContent = topContent
self.bottomContent = bottomContent
}
var body: some View {
VStack {
topContent()
Spacer()
if bottomContent != nil {
bottomContent!()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但我收到此错误:
函数构建器属性“ViewBuilder”只能应用于函数类型的参数。
谢谢。
Asp*_*eri 16
考虑到buildIf的特征ViewBuilder的以下方法是可能的,其允许保持ViewBuilder在init(即优选的)
经测试适用于 Xcode 11.2 / iOS 13.2
struct TopAndBottomView<Content>: View where Content: View {
let topContent: () -> Content
let bottomContent: () -> Content?
init(@ViewBuilder topContent: @escaping () -> Content,
@ViewBuilder bottomContent: @escaping () -> Content? = { nil }) {
self.topContent = topContent
self.bottomContent = bottomContent
}
var body: some View {
VStack {
topContent()
Spacer()
bottomContent()
}
}
}
Run Code Online (Sandbox Code Playgroud)
所以像这个一样工作
struct TopAndBottomView_Previews: PreviewProvider {
static var previews: some View {
TopAndBottomView(topContent: {
Text("TOP")
}, bottomContent: {
Text("BOTTOM")
})
}
}
Run Code Online (Sandbox Code Playgroud)
和这个
struct TopAndBottomView_Previews: PreviewProvider {
static var previews: some View {
TopAndBottomView(topContent: {
Text("TOP")
})
}
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*hew 10
@JoeBayLD 问:
如果 topContent 和 bottomContent 是不同的视图类型,你会怎么做?我创建了一个新的通用属性,但是当使用默认的“nil”参数时,任何调用者都无法推断内容类型
您可以将两个 ViewBuilder 参数设为非可选,然后通过扩展来处理“无底部内容”的情况where BottomContent == EmptyView:
struct TopAndBottomView<TopContent: View, BottomContent: View>: View {
let topContent: TopContent
let bottomContent: BottomContent
init(@ViewBuilder topContent: () -> TopContent,
@ViewBuilder bottomContent: () -> BottomContent) {
self.topContent = topContent()
self.bottomContent = bottomContent()
}
var body: some View {
VStack {
topContent
Spacer()
bottomContent
}
}
}
extension TopAndBottomView where BottomContent == EmptyView {
init(@ViewBuilder topContent: () -> TopContent) {
self.init(topContent: topContent, bottomContent: { EmptyView() })
}
}
// usage
TopAndBottomView(topContent: { Text("hello") })
TopAndBottomView(topContent: { Text("hello") }, bottomContent: { Text("world") })
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2364 次 |
| 最近记录: |