Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@FocusState with programaticly generated TextField

Tags:

swiftui

I'm trying to create a list of TextFields base on an array of strings, when the return key is pressed on the keyboard, I want to create a new TextField and focus it with the new @FocusState SwiftUI attribut

I've build a view like so:

struct ContentView: View {
    
    @State var list: [String] = [""]
    
    @FocusState private var focusField: Int?
    
    var body: some View {

        List {
            ForEach($list.indices, id: \.self) { idx in
                TextField("placeholder", text: $list[idx])
                    .focused($focusField, equals: idx)
                    .submitLabel(.next)
                    .onSubmit {
                        list.insert("", at: idx + 1)
                        focusNextField(from: idx)
                    }
            }
        }

    }
    
    private func focusNextField(from index: Int) {
        focusField = index + 1
    }
}

The issue is in the focusNextField(from index: Int) method if I print focusField after focusField = index + 1 it give me the same value as index. Any idea how could I solve this?

like image 772
Jonathan Avatar asked Sep 10 '25 12:09

Jonathan


1 Answers

Came across this question as I'm about to embark on something similiar, guessing maybe already cracked, but for the benefit of others less fortunate :-)

So currently it turns out to make this work with macOS v12 (Monterey) Beta 6 and Xcode 13 Beta 5 it's necessary to specifically set the FocusState for the next "app state" outside of the current "app state"'s UI update cycle e.g.

import SwiftUI

struct ContentView: View {
    @State var fields: [String] = [""]

    @FocusState private var focusField: Int?

    var body: some View {
        List {
            ForEach($fields.indices, id: \.self) { idx in
                TextField("placeholder", text: $fields[idx])
                    .focused($focusField, equals: idx)
                    .submitLabel(.next)
                    .onSubmit {
                        fields.insert("", at: idx + 1)
                        focusNextField(from: idx)
                    }
            }
        }

        .onAppear { /// Focus on initial field
            guard fields.count > 0 else { return }
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
                focusField = 0
            }
        }
    }

    private func focusNextField(from index: Int) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            focusField = index + 1
        }
    }
}

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

Fwiw, given how this is likely to be used this seems a bit odd, possibly even a bug and I'd suggest submitting Feedback to Apple as such for anyone else who thinks so.

like image 111
shufflingb Avatar answered Sep 13 '25 05:09

shufflingb