我正在为我的应用程序开发 UI,它使用 Realm 作为后端。用户在自定义 TextField 中输入文本,该 TextField 使用“浮动”标签来有效利用屏幕。标签动画(由非常简单的逻辑支持)是通过检查 Realm 对象的属性和自定义 View 之间的 Binding 状态来触发的。
当我对视图进行原型设计时,我使用了由结构支持的 @State 或 @Binding 属性,并且视图的行为完全符合预期。但是,当在我的主应用程序中使用它时,@State 或 @Binding 包装一个类(一个领域对象)并且永远不会触发转换,当然是因为视图没有注册其内部状态的更改,所以它不是重新-随着颜色和偏移的变化而渲染。
当我意识到在处理类时应该使用@ObservableObject 时,我认为我有解决方案,但这也不起作用。仔细想想,这似乎是有道理的,尽管我对各种属性包装器的工作方式有点困惑。
我非常怀疑有一个解决方法,我的第一个停靠港可能会挂接到 willChange 以修改必要的状态。但是,与此同时,有人可以解释这里发生了什么,因为我有点朦胧。如果你碰巧有一个解决方案,这可能会阻止我走上一些疯狂的切线?
自定义视图:
struct FloatingLabelTextField: View {
let title: String
let text: Binding<String>
let keyboardType: UIKeyboardType?
let contentType: UITextContentType?
var body: some View {
ZStack(alignment: .leading) {
Text(title)
.foregroundColor(text.wrappedValue.isEmpty ? Color(.placeholderText) : .accentColor)
.offset(y:text.wrappedValue.isEmpty ? 0 : -25)
.scaleEffect(text.wrappedValue.isEmpty ? 1 : 0.8, anchor: .leading)
TextField("", text: text, onEditingChanged: { _ in print("Edit change") }, onCommit: { print("Commit") })
.keyboardType(keyboardType ?? .default)
.textContentType(contentType ?? .none)
}
.padding(15)
.border(Color(.placeholderText), width: 1)
.animation(.easeIn(duration: 0.3))
}
}
功能实现:
struct MyView: View {
@State private var test = ""
var body: some View {
VStack {
FloatingLabelTextField(title: "Test", text: $test, keyboardType: nil, contentType: nil)
}
}
}
或者...
struct TestData {
var name: String = ""
}
struct ContentView: View {
@State private var test = TestData()
var body: some View {
VStack {
FloatingLabelTextField(title: "Test", text: $test.name, keyboardType: nil, contentType: nil)
}
}
将@State/@Binding 与对象一起使用:
class TestData: ObservableObject {
var name: String = ""
}
struct ContentView: View {
@ObservedObject private var test = TestData()
var body: some View {
VStack {
FloatingLabelTextField(title: "Test", text: $test.name, keyboardType: nil, contentType: nil)
}
}