我尝试解开我的可选属性,但收到此错误消息:包含控件流语句的闭包不能与函数生成器“ ViewBuilder”一起使用
我看不到代码有什么问题
代码:
HStack {
if let height = profile.height {
TagBox(field: "height", value: String(height))
}
TagBox(field: "nationality", value: profile.nationality)
Spacer()
}.padding(.horizontal)
答案 0 :(得分:3)
在这种情况下,有两种使用可选方法的方法:
第一个,如果您不希望此视图在profile.height为nil时完全显示:
profile.height.map({ TagBox(field: "height", value: String($0))})
第二个,如果要显示此视图,但使用默认值:
TagBox(field: "height", value: String(profile.height ?? 0))
答案 1 :(得分:1)
现在在ViewBuilder
中使用条件绑定非常好:
HStack {
if let height = profile.height { // <- This works now in Xcode 12
TagBox(field: "height", value: String(height))
}
TagBox(field: "nationality", value: profile.nationality)
Spacer()
}.padding(.horizontal)
答案 2 :(得分:0)
您可以在Group
的视图构建器中使用if语句。我举了一个例子来说明:
var label1 = "label 1"
@State var label2: String?
var label3: String? = "label 3"
var body: some View {
VStack {
Text(label1)
Group {
if label2 != nil {
Text(label2!)
}
if label3 != nil {
Text(label3!)
}
}
Button(action: {
self.label2 = "Button pressed!"
}) {
Text("Press me!")
}
}
}
当然,在此示例中,您可以执行Text(label2 ?? "")
,但是在Text
拥有值之前,label2
会有一个空白,而且更复杂在这种情况下,可以提供更大的灵活性。如果运行该代码,则将在“标签3”的正上方看到“标签1”,如果您按下按钮,则“按下按钮!”。将出现在“标签1”和“标签3”之间。
基本上,如果label2
为nil,则当标签具有值时,将没有空格,而是没有间隙,并且当label2
被分配了值,应该在其之上和之下的所有内容都会发生变化以适应它。
在您提供的代码中,您可以将其更改为:
HStack {
Group {
if profile.height != nil {
TagBox(field: "height", value: String(profile.height!))
}
}
TagBox(field: "nationality", value: profile.nationality)
Spacer()
}.padding(.horizontal)
此解决方案的好处是,您可以在值为nil(或不为nil)的情况下做更复杂的事情,甚至在值为nil的情况下甚至提供默认视图(在我的示例中,这是等同于添加一个else
if
内的Button
,Text
等带有else
,ViewBuilder
等的语句。
一个缺点是您必须显式地解开可选对象,这不应该成为问题,因为if语句可以确保它不是nil,但是我仍然发现可选绑定通常是一种更干净的解包途径。
修改:
如果您确实不想显式拆开可选选项,则可以使用var label1 = "label 1"
@State var label2: String?
var label3: String? = "label 3"
var body: some View {
VStack {
Text(label1)
Group {
self.conditionalText(self.label2)
if label3 != nil {
Text(label3!)
}
}
Button(action: {
self.label2 = "Button pressed!"
}) {
Text("Press me!")
}
}
}
func conditionalText(_ text: String?) -> some View {
if let text = text {
return ViewBuilder.buildIf(Text(text))
} else {
print("Text is nil")
}
let view: Text? = nil
return ViewBuilder.buildIf(view)
}
s:
Group
此方法还着重说明了{{1}}内的可执行代码,只要该代码位于返回视图的函数中即可。
答案 3 :(得分:0)
因此,如果用力拉开会使您感到不舒服,则可以使用我创建的以下自定义视图:
struct OptionalView<Value, Content>: View where Content: View {
var content: (Value) -> Content
var value: Value
init?(_ value: Value?, @ViewBuilder content: @escaping (Value) -> Content) {
guard let value = value else {
return nil
}
self.value = value
self.content = content
}
var body: some View {
content(value)
}
}
并像这样使用它:
OptionalView(profile.height) { height in
TagBox(field: "height", value: String(height))
}
我写了一篇有关此问题的文章,并提出了一系列可选视图here