@State更新视图,但@ObservedObject不更新

时间:2020-06-16 00:54:35

标签: swift xcode swiftui

我有一个观点:

TextArea

其中.validation(message: model.details.message)是自定义视图,而FormInput是自定义视图修饰符。我的final class FormInput: ObservableObject { @Published var details: TextInput // ... other code } 如下所示:

TextInput

Form是自定义结构。

现在,当我运行上述代码时,验证不会触发,因为Form不会重新渲染,但是如果我将 struct MyForm: View { @State var details = TextInput() var body: some View { Form { TextArea("Details", text: $details.value) .validation(message: details.message) } } } 更改为:

Form

然后一切正常。为什么视图会针对Form的第二个版本而不是第一个版本进行渲染?由于detailsdetails@Published观察到这些变化时,Form发生变化时,final class FormInput: ObservableObject { @Published var details: TextInput init(details: String = "") { self.details = TextInput(value: details, isValid: false, validations: [.length(12)]) } // other code } struct TextInput { var value: String { didSet { self.validate() } } var validations: [TextValidation] // this is just an enum of different types of validations var isValid: Bool var message: String mutating func validate() { for validation in validations { // run validation } } } struct TextArea: View { @Binding var text: String @State var height: CGFloat = 12 init(text: Binding<String>) { self._text = text } var body: some View { TextAreaField(text: $text) } } struct TextAreaField: UIViewRepresentable { @Binding var text: String @Binding var height: CGFloat func makeUIView(context: Context) -> UITextView { let textField = UITextView() textField.isEditable = true textField.isSelectable = true textField.isUserInteractionEnabled = true textField.isScrollEnabled = false // ..other initializers removed for brevity textField.delegate = context.coordinator return textField } func updateUIView(_ uiView: UITextView, context: Context) { calculateHeight(uiView) } func calculateHeight(_ uiView: UIView) { let newSize = uiView.sizeThatFits(CGSize(width: uiView.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) if self.height != newSize.height { DispatchQueue.main.async { self.height = newSize.height } } } func makeCoordinator() -> Coordinator { return Coordinator(self) } final class Coordinator: NSObject, UITextViewDelegate { var parent: TextAreaField init(_ parent: TextAreaField) { self.parent = parent } func textViewDidChange(_ uiView: UITextView) { self.parent.text = uiView.text self.parent.calculateHeight(uiView) } } } struct Validation: ViewModifier { let message: String func body(content: Content) -> some View { let isValid = message == "" print(message) return VStack(alignment: .leading) { content if isValid == false { Text(message) .font(.footnote) .italic() .foregroundColor(Color.red) .frame(height: 24) } } .padding(.bottom, isValid ? 24 : 0) } } extension View { func validation(message: String) -> some View { self.modifier(Validation(message: message)) } } 是否不应该更新?

附加上下文

以下是上述组件的其他代码

VideoView videoView = findViewById(R.id.videoView);
        videoView.setVideoPath("android.resource://" + getPackageName() + "/" + R.raw.sample);
        videoView.start();

1 个答案:

答案 0 :(得分:1)

我认为问题出在缺少自定义组件。因为在下面的简单演示中,提供的基础结构的复制实际上可以按预期与ObservableObject一起很好地工作。

通过Xcode 11.4 / iOS 13.4测试。与下面的演示进行比较可能有助于查找代码中缺少的内容。

demo

struct TextInput {
    var value: String = "" {
        didSet {
            message = value    // just duplication for demo
        }
    }
    var message: String = ""
}

// simple validator highlighting text when too long
struct ValidationModifier: ViewModifier {
    var text: String

    func body(content: Content) -> some View {
        content.foregroundColor(text.count > 5 ? Color.red : Color.primary)
    }
}

extension View {   // replicated 
    func validation(message: String) -> some View {
        self.modifier(ValidationModifier(text: message))
    }
}

struct MyForm: View {    // avoid same names with standard views
  @ObservedObject var model = FormInput()

  var body: some View {
    Form {
      TextField("Details", text: $model.details.value) // used standard
        .validation(message: model.details.message)
    }
  }
}

final class FormInput: ObservableObject {
  @Published var details: TextInput = TextInput()
}

struct TestObservedInModifier: View {
    var body: some View {
        MyForm()
    }
}
相关问题