[英]Unable to update/modify SwiftUI View's @state var
I'm unable to update the ExampleView's message
var even though I can see updateMessage()
is being called.即使我可以看到正在调用
updateMessage()
我也无法更新 ExampleView 的message
updateMessage()
。 Here is my simplified/convoluted SwiftUI example of Playground code that isn't working.这是我的 Playground 代码的简化/复杂 SwiftUI 示例,但它不起作用。 The
message
var does not get updated when called in updateMessage()
.该
message
在调用时变种没有更新updateMessage()
As a result, the UI Text()
is not updated either.因此,UI
Text()
也不会更新。
Why is the @State var message
not updating?为什么@State var
message
没有更新? What is the correct way to update it?更新它的正确方法是什么?
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())
You should only change State
of a view Inside it's own body block.您应该只在它自己的主体块内更改视图的
State
。 If you need to change it from a parent view, you may want to pass the value to it from parent and make it Binding
instead.如果您需要从父视图更改它,您可能希望将值从父视图传递给它并改为
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)
}
}
If you need to encapsulate messages inside the ExampleView
, you can use a Bool
(or an enum
or etc) instead:如果您需要在
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)
}
}
actually, the variable does get updated, but your Content view doesn't get informed about it.实际上,该变量确实会更新,但您的 Content 视图并未获知它。 This is what happens:
这是发生的事情:
now, you have different options: @State
, @Binding
and @PublishedObject, @ObservedObject
.现在,您有不同的选择:
@State
、 @Binding
和@PublishedObject, @ObservedObject
@State
、 @Binding
@PublishedObject, @ObservedObject
。 You need one of these Publishers, so your view actually notices that it needs to do something.您需要这些发布者之一,因此您的视图实际上会注意到它需要做一些事情。
Either you draw a new ExampleView
every time you press the button, in this case you can use a @State
variable in ContentView
:每次按下按钮时都绘制一个新的
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)
}
}
which is probably not what you want.这可能不是你想要的。
Next, you can use @Binding which was already suggested.接下来,您可以使用已经建议的@Binding 。
And last, you can use ObservableObject @ObservedObject, @Published最后,你可以使用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)
}
}
what this says is: class ExampleState: ObservableObject
- this class has published variables that can be observed这说的是:
class ExampleState: ObservableObject
- 这个类已经发布了可以观察的变量
to resume (that's how I understand it):恢复(这就是我的理解):
ContentView
and ExampleView
: if state.message
(any value that state
publishes) changes, you need to redraw your body" ContentView
和ExampleView
:如果state.message
( state
发布的任何值)发生变化,你需要重绘你的身体”ExampleState
: after updating your message variable, publish the new value!" ExampleState
:更新您的消息变量后,发布新值!” lastly - for completion - there is @EnvironmentObject
, as well, that way you'd only have to pass the variable to the top-views and everything down the view hierarchy would inherit it.最后 - 为了完成 - 还有
@EnvironmentObject
,这样你只需要将变量传递给顶视图,视图层次结构中的所有内容都会继承它。
One of the solutions that should work, but as guys say, you can work with @Binding
应该可行的解决方案之一,但正如人们所说,您可以使用
@Binding
struct ExampleView: View {
var message: String = "Hello"
var body: some View {
Text(self.message)
}
mutating func updateMessage() {
print("updateMessage ran")
message = "Updated"
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.