@State更新视图,但@ObservedObject不更新视图
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了@State更新视图,但@ObservedObject不更新视图相关的知识,希望对你有一定的参考价值。
我有一个观点。
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
看起来如下。
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
在第一种情况下,更新时 details
变化以来 details
是 @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))
}
}
答案
我想问题出在没有自定义组件的地方。因为下面简单的演示复制所提供的基础架构工作得很好。ObservableObject
,其实和预期一样。
用Xcode 11.4 ios 13.4测试。与下面的演示进行比较,可能会有助于找到你的代码中的遗漏之处。
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()
}
}
以上是关于@State更新视图,但@ObservedObject不更新视图的主要内容,如果未能解决你的问题,请参考以下文章
StateObject 属性不会更新视图,但 ObservedObject 会