raw3d
raw3d

Reputation: 3515

SwiftUI how to get reference to editing Textfield inside a List?

Is it possible to find a particular view in SwiftUI based on its tag ? Or is there another solution to my problem below ?

Based on string in a Textfield in a Row in List A, am populating search results in List B.

When a row on a List B is tapped, I want the textField on List A to be updated. But the problem is I dont know how to get hold of the active textField or the index of the row in the List A.

Please refer this image for clarity enter image description here

Im trying to emulate this behaviour, which is common in desktop. You enter text in a Textfield and either using mouse or up down arrow keys to select an option and the Textfield gets updated with that option.

enter image description here

Here instead of PopOver am using a separate List view.

Upvotes: 1

Views: 4066

Answers (1)

kontiki
kontiki

Reputation: 40519

In the code below, you can see how to accomplish most of the things you require.

You mention you want to know which field you are typing on. You can do that by using the onEdintingChanged closure. This closure receives a boolean value that indicates if the field became active or inactive. You can use it to set a variable like in the example: activeField.

Another of your requests, was being able to refresh the List with every keystroke. The onReceive modifier subscribes to the binding of the TextField and executes your closure for each. There is however, what I think it is a bug: When there is text in both fields, the closure executes for both fields at every keystroke. The if statement comparing self.activeField is there to prevent that.

So, now, from the closure you can trigger an update on your external model. Since your List should be bound to the same model, it will refresh automatically.

Another of your requirements was that tapping on the list should update your text field. That is simple. If your textfield is bound to the same model, you just update the corresponding model variable and the field will update.

I hope I've been clear.

struct ContentView : View {
    @State private var field1 = ""
    @State private var field2 = ""

    @State private var activeField: Int = 0

    var body: some View {
        VStack {
            TextField("", text: $field1, onEditingChanged: { if $0 { self.activeField = 0 } })
                .textFieldStyle(.roundedBorder)
                .onReceive(field1.publisher().last()) { if self.activeField == 0 { print("FIELD 1 -> \(self.field1): \($0)") } }

            TextField("", text: $field2, onEditingChanged: { if $0 { self.activeField = 1 } })
                .textFieldStyle(.roundedBorder)
                .onReceive(field2.publisher().last()) { if self.activeField == 1 { print("FIELD 2 -> \(self.field2): \($0)") } }
        }
    }
}

Upvotes: 6

Related Questions