子视图未触发父视图中的禁用状态更新SwiftUI

mqkwyuun  于 2023-04-19  发布在  Swift
关注(0)|答案(3)|浏览(146)

我有几个嵌套视图,其中包含需要确保验证的嵌套viewModel。
本质上,ViewA有一个表单、一个Submit按钮和一个Subview(ViewB)-ViewB的ViewModel包含在ViewB中由于无聊的业务原因,此架构无法更改ViewB有一些表单字段。在启用Submit按钮之前,我需要确保ViewA和ViewB中的所有字段都有效。
我似乎不知道如何做到这一点,因为ViewB中的任何更改都不会触发ViewA的刷新
下面是一些简化的代码作为一个粗略的例子

class ViewModelB: ObservableObject {
    @Published var text = ""
    @Published var textTwo = ""
    
    func isValid() -> Bool {
        !text.isEmpty && !textTwo.isEmpty
    }
}

class ViewModelA: ObservableObject {
    @Published var text = ""
    @ObservedObject var addressViewModel: ViewModelB = ViewModelB()

    func isValid() -> Bool {
        print("is Valid called")
        return !text.isEmpty && addressViewModel.isValid()
    }
}
struct AddressView: View {
    @ObservedObject var viewModel: ViewModelB

    init(addressModel:ViewModelB) {
        self.viewModel = addressModel
    }
    var body: some View {
        TextField("View B Text", text: $viewModel.text)
        TextField("View B TextTwo", text: $viewModel.textTwo)
    }
}

struct ContentView: View {
    @StateObject var viewModel: ViewModelA = ViewModelA()

    var body: some View {
        VStack {
            TextField("View A Text", text: $viewModel.text)
            AddressView(addressModel: viewModel.addressViewModel)
            Button("Apply Button") {
                print("Button tapped!")
            }.disabled(!viewModel.isValid() || !viewModel.addressViewModel.isValid())
        }
    }
}
b09cbbtk

b09cbbtk1#

将AddressView中的ViewModelB更改为Binding而不是ObservedObject,以及在ViewModelA中将其更改为Published而不是ObservedObject,可以解决此问题。
我猜这是因为SwiftUI的观察变化的机制只在一个级别的对象上起作用,并且不会自动将更新传播到嵌套的对象。
请在下面找到完整的代码。

class ViewModelB: ObservableObject {
    @Published var text = ""
    @Published var textTwo = ""
    
    func isValid() -> Bool {
        !text.isEmpty && !textTwo.isEmpty
    }
}

class ViewModelA: ObservableObject {
    @Published var text = ""
    @Published var addressViewModel: ViewModelB = ViewModelB()
    
    func isValid() -> Bool {
        print("is Valid called")
        return !text.isEmpty && addressViewModel.isValid()
    }
}

struct AddressView: View {
    @Binding var viewModel: ViewModelB
    
    var body: some View {
        TextField("View B Text", text: $viewModel.text)
        TextField("View B TextTwo", text: $viewModel.textTwo)
    }
}

struct ContentView: View {
    @StateObject var viewModel: ViewModelA = ViewModelA()
    
    var body: some View {
        VStack {
            TextField("View A Text", text: $viewModel.text)
            AddressView(viewModel: $viewModel.addressViewModel)
            Button("Apply Button") {
                print("Button tapped!")
            }.disabled(!viewModel.isValid() || !viewModel.addressViewModel.isValid())
        }
    }
}
u91tlkcl

u91tlkcl2#

尝试使用这个:

@Published var addressViewModel: ViewModelB = ViewModelB()

而不是这样:

@ObservedObject var addressViewModel: ViewModelB = ViewModelB()
raogr8fs

raogr8fs3#

您应该在ContentView中添加addressViewModel,以便视图在更改时刷新,或者您可以按照以下答案操作:How to tell SwiftUI views to bind to nested ObservableObjects
另外请注意,我们在SwiftUIView s中只使用@ObservedObject

相关问题