0

バックエンドに Realm を使用するアプリの UI を開発しました。テキストは、画面を効率的に使用するために「フローティング」ラベルを使用するカスタマイズされた TextField にユーザーが入力します。ラベル アニメーション (非常に単純なロジックに基づく) は、Realm オブジェクトのプロパティとカスタム ビューの間の 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)
    }
}

オブジェクトの使用

4

2 に答える 2