【问题标题】:How we can read @State variable from other struct in SwiftUI?我们如何从 SwiftUI 中的其他结构中读取 @State 变量?
【发布时间】:2020-10-28 15:24:16
【问题描述】:

我想知道是否有简单或正确的方法从不同的视图读取状态变量值,我知道 .onChange 或 Binding 或 ObservableObject(class) 的用法和...,但我想知道的是还有其他更好的方法吗?

例如,在这段代码中,我有一个名为 TextView 的视图,它有一个状态值,我在我的 ContentView 中调用这个视图,现在我在我的 ContentView 中放置一个文本,我想读取 TextView 的状态值。这项工作有空间方法吗?

struct ContentView: View {
    @State var readStringOfTextView: String = ""

    var body: some View {
        TextView()

        Text(readStringOfTextView)
            .foregroundColor(Color.blue)
    }
}

struct TextView: View {
    @State var stringOfText: String = "Hello, world!"

    var body: some View {
        Text(stringOfText)
            .padding()
            .foregroundColor(Color.red)
    }
}

【问题讨论】:

    标签: swiftui


    【解决方案1】:

    State 的全部意义在于它在 View 的内部。如果您尝试在其他地方阅读它,那么您的设计中出现了问题。在这种情况下,您需要的工具是 @Binding。 ContentView 应该将 Binding 传递给 TextView。 ContentView 将看到 TextView 中的任何更改(在您的示例中,这没有意义,因为stringOfText 无法更改,但我假设您的其余代码会以某种方式更改它)。在您的示例中,这看起来像这样:

    struct ContentView: View {
        @State var readStringOfTextView: String = ""
        var body: some View {
            TextView(stringOfText: $readStringOfTextView)
            Text(readStringOfTextView)
                .foregroundColor(Color.blue)
        }
    }
    
    struct TextView: View {
        @Binding var stringOfText : String
    
        var body: some View {
            Text(stringOfText)
                .padding()
                .foregroundColor(Color.red)
                .onAppear {
                    stringOfText = "Hello, world!"
                }
        }
    }
    

    可以使用首选项直接将数据向上传递到视图层次结构,但它要复杂得多,而且不是解决您所描述问题的正确工具。即便如此,它是这样的:

    • 创建一个 PreferenceKey 来传递数据
    • 使用.preference 在子视图中设置 PreferenceKey
    • 使用.onPreferenceChange.overlayPreferenceValue.backgroundPreferenceValue读取父视图中的PreferenceKey。
    struct TextPreference: PreferenceKey {
        static var defaultValue = "default"
        static func reduce(value: inout String, nextValue: () -> String) {
            value = nextValue()
        }
    }
    
    struct ContentView: View {
        @State var readStringOfTextView: String = ""
    
        var body: some View {
            VStack {
                TextView()
                    .onPreferenceChange(TextPreference.self) { value in
                        readStringOfTextView = value
                    }
                Text(readStringOfTextView)
                    .foregroundColor(Color.blue)
            }
        }
    }
    
    struct TextView: View {
        @State var stringOfText : String = "Hello, world!"
    
        var body: some View {
            Text(stringOfText)
                .padding()
                .foregroundColor(Color.red)
                .preference(key: TextPreference.self, value: stringOfText)
        }
    }
    

    【讨论】:

    • 正如我所说,我已经知道 State 和 Binding 的用法,. . . TextView 是没有观察到的东西!你把绑定放在那里!请看我的代码。我想阅读 TextView 的状态,也许更接近和更合乎逻辑的方式是 ObservableObject 在 TextView 和 ContentView 之间共享,有人可以读或写,我正在寻找更好的方法
    • 是的,如果您有状态希望多个视图都观察和共享,ObservableObject 将是正确的工具。您不得阅读其他视图状态。状态是明确的内部的。首选项也适用于此,但通常不是您所描述的那种东西的正确工具。如果它是“类似模型的”,那么您需要一个 Observable。
    • 所以,这就是我问这个问题的原因,我不确定是否有比 ObservableObject 方法更好的方法!当我要使用 ObservableObject 时,我正在做颠倒的工程来解决这个问题,在这种情况下,我使用的不是 State 而是 StateObject,所以说 State 不能从外部访问,但 StateObject 是正确的! !我可以说最好和正确的答案是 StateObject 吗?
    • StateObject 为 View 提供了一些原本是 ObservedObject 的东西的所有权。这很方便,因为这意味着在顶级视图中,您不需要传入对象。但您仍然不能尝试询问子视图的 StateObjects。 “状态”的东西总是私有的。视图永远不是更高级别视图(或系统的其他部分)状态的所有者。 WWDC20:developer.apple.com/videos/play/wwdc2020/10040
    猜你喜欢
    • 2019-12-16
    • 2017-03-20
    • 2019-11-10
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 2019-03-03
    • 2023-01-18
    • 1970-01-01
    相关资源
    最近更新 更多