首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >@State更新视图,但@State没有

@State更新视图,但@State没有
EN

Stack Overflow用户
提问于 2020-06-16 00:54:35
回答 1查看 69关注 0票数 2

我的看法是:

代码语言:javascript
复制
struct Form: View {
  @ObservedObject var model = FormInput()

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

其中TextArea是自定义视图,.validation(message: model.details.message)是自定义视图修饰符。我的FormInput看起来如下:

代码语言:javascript
复制
final class FormInput: ObservableObject {
  @Published var details: TextInput

  // ... other code
}

TextInput是一个自定义结构。

现在,当我运行上面的代码时,验证永远不会触发,因为Form从不重新呈现,但是如果我将Form更改为:

代码语言:javascript
复制
 struct MyForm: View {
      @State var details = TextInput()

      var body: some View {
        Form {
          TextArea("Details", text: $details.value)
            .validation(message: details.message)
        }
      }
    }

然后一切都如预期的那样运作。为什么视图会呈现给第二个版本的Form,而不是第一个版本呢?在第一种情况下,Form不应该在details更改时更新吗?因为details@Published,而Form在观察更改吗?

附加上下文

下面是上述组件的附加代码

代码语言:javascript
复制
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))
  }
}
EN

回答 1

Stack Overflow用户

发布于 2020-06-16 07:30:35

我认为问题在于缺少自定义组件。因为下面提供的基础设施的简单演示复制可以很好地应用于ObservableObject,实际上就像预期的那样。

用Xcode 11.4 / iOS 13.4进行测试。与下面的示例相比,演示可能有助于找到代码中遗漏的内容。

代码语言:javascript
复制
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()
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62399338

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档