无法更新/修改 SwiftUI 视图的 @state var
Posted
技术标签:
【中文标题】无法更新/修改 SwiftUI 视图的 @state var【英文标题】:Unable to update/modify SwiftUI View's @state var 【发布时间】:2020-01-17 08:34:08 【问题描述】:我无法更新 ExampleView 的 message
var,即使我可以看到 updateMessage()
正在被调用。这是我的 Playground 代码的简化/复杂的 SwiftUI 示例,它不起作用。在 updateMessage()
中调用时,message
变量不会更新。因此,UI Text()
也不会更新。
为什么@State var message
没有更新?更新它的正确方法是什么?
import SwiftUI
import PlaygroundSupport
struct ContentView: View
let coloredLabel = ExampleView()
var body: some View
VStack
coloredLabel
.foregroundColor(Color.red)
.padding()
Button(action:
self.coloredLabel.updateMessage()
)
Text("Press me")
struct ExampleView: View
@State private var message: String = "Hello"
var body: some View
Text(self.message)
func updateMessage()
print("updateMessage ran") // this prints
self.message = "Updated"
PlaygroundPage.current.setLiveView(ContentView())
【问题讨论】:
您只能在其自己的body
块内设置视图的State
。您将ExampleView
的状态设置为ContentView.body
,这是不允许的。我认为这是你应该使用@Binding
的地方。
【参考方案1】:
您应该只更改视图 inside 自己的主体块的State
。如果您需要从父视图更改它,您可能希望将值从父视图传递给它并改为Binding
。
struct ContentView: View
@State private var message = "Hello"
var body: some View
VStack
ExampleView(message: $message)
.foregroundColor(Color.red)
.padding()
Button("Press me")
self.message = "Updated"
struct ExampleView: View
@Binding var message: String
var body: some View
Text(message)
如果您需要在ExampleView
中封装消息,可以使用Bool
(或enum
等)代替:
struct ContentView: View
@State private var updated = false
var body: some View
VStack
ExampleView(isUpdated: $updated)
.foregroundColor(Color.red)
.padding()
Button("Press me")
self.updated = true
struct ExampleView: View
@Binding var isUpdated: Bool
private var message: String isUpdated ? "Updated" : "Hello"
var body: some View
Text(message)
【讨论】:
您是否仅限于 Bool 或 enum?我想使用 Int,或者在示例中使用 String 不,您可以使用任何适合您的情况。关键是使用父级的binding
变量触发更改。
好的,我使用绑定示例让它工作了。我遇到的一个问题是在视图正文中使用Text(self.message)
。那是行不通的。它必须是Text(message)
。谢谢!【参考方案2】:
实际上,变量确实得到了更新,但您的内容视图并没有得到有关它的通知。这就是发生的事情:
ContentView 被调用,它用 ExampleView 初始化 coloredLabel 在 ContentView 中按下按钮 self.coloredLabel.updateMessage() 被调用 消息已打印 变量 self.coloredLabel.message 被修改 ContentView 不会重绘,因为它没有收到有关更改的通知 更具体地说,堆栈中的 coloredLabel 不会更新现在,您有不同的选择:
@State
、@Binding
和 @PublishedObject, @ObservedObject
。您需要其中一个发布者,因此您的视图实际上注意到它需要做某事。
要么在每次按下按钮时绘制一个新的ExampleView
,在这种情况下,您可以在ContentView
中使用@State
变量:
struct ContentView: View
@State private var string = "Hello"
var body: some View
VStack
ExampleView(message: string)
.foregroundColor(Color.red)
.padding()
Button(action:
self.string = "Updated"
)
Text("Press me")
struct ExampleView: View
var message: String
var body: some View
Text(self.message)
这可能不是你想要的。
接下来,您可以使用已经建议的 @Binding。
最后,你可以使用 ObservableObject @ObservedObject, @Published
class ExampleState: ObservableObject
@Published var message: String = "Hello"
func update()
message = "Updated"
struct ContentView: View
@ObservedObject var state = ExampleState()
var body: some View
VStack
ExampleView(state: state)
.foregroundColor(Color.red)
.padding()
Button(action:
self.state.update()
)
Text("Press me")
struct ExampleView: View
@ObservedObject var state: ExampleState
var body: some View
Text(state.message)
这句话的意思是:
class ExampleState: ObservableObject
- 这个类已经发布了可以观察的变量
继续(我是这么理解的):
“嘿,ContentView
和 ExampleView
:如果 state.message
(state
发布的任何值)发生变化,您需要重新绘制身体”
“和ExampleState
:更新你的消息变量后,发布新值!”
最后-为了完成-还有@EnvironmentObject
,这样您只需将变量传递给顶层视图,视图层次结构中的所有内容都会继承它。
【讨论】:
【参考方案3】:应该可行的解决方案之一,但正如人们所说,您可以使用@Binding
struct ExampleView: View
var message: String = "Hello"
var body: some View
Text(self.message)
mutating func updateMessage()
print("updateMessage ran")
message = "Updated"
【讨论】:
以上是关于无法更新/修改 SwiftUI 视图的 @state var的主要内容,如果未能解决你的问题,请参考以下文章
在 SwiftUI 中使用 Map 时在视图更新期间获取修改状态