在@ViewBuilder闭包中更改@State

sup*_*cio 0 ios swift swiftui

我试图了解如何更改闭包中的@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!")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我遇到一些错误:

错误1:

函数声明了一个不透明的返回类型,但是在其主体中没有用于从其推断基础类型的返回语句

但这return是多余的,因为在View计算属性内只有一行代码。

错误2:

无法将类型'GeometryReader <_>'的返回表达式转换为返回类型'some View'

既然我明确地写return Text("...")了,那类型就不应该清楚吗?

这是什么问题

Pro*_*in8 5

首先,您不能在中做出任意的swift语句functionBuilder。允许使用特定的语法。在SwiftUI的情况下,它是一个ViewBuilder,它在幕后构成您的类型。当您在SwiftUI中创建连续的语句时,实际上是在依赖编译器根据该DSL的规则在其下编写新类型。

第二,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.")
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么出现钝性错误的原因:

无法将类型'GeometryReader <_>'的返回表达式转换为返回类型'some View'

该类型的系统不能建立任何View出来的View,基本上Void当你执行:

self.width = geometry.size.width

当您View在下面执行连续语句时,它仍将被转换为一种新的类型View

// the result of this is TupleView<Text, Text>
Text("left")
Text("right")
Run Code Online (Sandbox Code Playgroud)