我试图了解如何在@State
闭包中更改@ViewBuilder
变量。以下只是一个简单的示例:
struct ContentView: View {
@State var width = CGFloat(0)
var body: some View { //Error 1
GeometryReader { geometry in //Error 2
self.width = geometry.size.width
return Text("Hello world!")
}
}
}
我遇到一些错误:
错误1:
函数声明了不透明的返回类型,但是没有返回语句 从其主体中推断出基础类型
但是return
是多余的,因为View
计算属性内只有一行代码。
错误2:
无法将类型为'GeometryReader <_>'的返回表达式转换为return 输入“某些视图”
自从我明确写出return Text("...")
以来,类型不应该清晰吗?
这是什么问题?
答案 0 :(得分:5)
首先,您不能在functionBuilder
中进行任意swift语句。允许使用特定的语法。在SwiftUI的情况下,它是一个ViewBuilder
,实际上是在组成您的类型。在SwiftUI中执行连续语句时,实际上是在依赖编译器根据该DSL的规则在其下编写新类型。
2,SwiftUI是一个配方,不是事件系统。您不必在body
函数中更改状态变量,而是可以设置状态变量在外部更改时应如何反应。如果希望另一个视图对该宽度做出某种反应,则需要根据所需组件的宽度定义该内容。不知道您的最终目标是什么,很难回答如何将内容相互关联。
编辑:
我被要求详细说明允许的范围。每个functionBuilder
都有一个不同的允许语法,这些语法在functionBuilder
本身中定义。这对Swift 5.1中的函数构建器有很好的概述:https://www.swiftbysundell.com/posts/the-swift-51-features-that-power-swiftuis-api
至于SwiftUI到底在寻找什么,它实质上是在寻找每条语句返回View
的实例。
// works fine!
VStack {
Text("Does this")
Text("Work?")
}
// doesn't work!
VStack {
Text("Updating work status...")
self.workStatus = .ok // this doesn't return an instance of `View`!
}
// roundabout, but ok...
VStack {
Text("Being clever")
gimmeView()
}
// fine to execute arbitrary code now, as long as we return a `View`
private func gimmeView() -> some View {
self.workingStatus = .roundabout
return Text("Yes, but it does work.")
}
这就是为什么出现钝角错误的原因:
无法将“ GeometryReader <_>”类型的返回表达式转换为“某些视图”类型
执行时,类型系统不能从View
到View
中构造任何Void
,
self.width = geometry.size.width
当您在下面执行连续的View
语句时,它仍将转换为新的View
类型:
// the result of this is TupleView<Text, Text>
Text("left")
Text("right")