fawsha1
fawsha1

Reputation: 790

SwiftUI - How to modify textfield in an array

In the following code, which you can copy into a new SwiftUI project, when I run it and start typing into the textfield, the field loses focus after each character. How can I fix this? I dont understand about observable objects so perhaps this is the problem? and BTW, I'm using Xcode 13.0 Beta 5

struct CmdOption: Hashable, Identifiable {
    var id: UUID { UUID() }
    var value: String
}

import SwiftUI

struct ContentView: View {
    
    @State var theOptions: [CmdOption] = [
        CmdOption(value: ""),
        CmdOption(value: "")
    ]
    
    @State var allOptions: [CmdOption] = []
    
    var body: some View {
        VStack {
            ScrollView(.vertical) {
                ForEach($allOptions, id: \.self)  { $option in
                    VStack {
                        TextField(option.value, text: $option.value)
                    }
                }
            }
        }.onAppear {
            startup()
        }
    }
    func startup() {
        allOptions.removeAll()
        theOptions.forEach {option in
            allOptions.append(option)
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Upvotes: 2

Views: 539

Answers (1)

George
George

Reputation: 30411

There are two problems:

  1. You have id as a computed property. This means that is will change every time you try read the value.
  2. You are using id: \.self, which is not unique (since id was also stored as a computed property, it isn't considered for default Hashable conformance).

To fix this, change CmdOption to the following:

struct CmdOption: Hashable, Identifiable {
    let id: UUID = UUID()
    var value: String
}

And your ForEach (implicitly id: \.id):

ForEach($allOptions) { $option in
    VStack {
        TextField(option.value, text: $option.value)
    }
}

Now, these view's IDs are constant and unique. The TextFields will now no longer lose focus, because they aren't recreating the view every time ContentView's body is recomputed, as their ID has remained the same. See Demystify SwiftUI - WWDC21 to learn more about how IDs affect a view's lifecycle.

Upvotes: 1

Related Questions