I have a list of text views where I would like to switch the focus after the next key has been pressed. I have a struct which represents my text field data:
struct WordEntry : BaseIndexStruct, Identifiable, Equatable, Hashable{
let id = UUID()
var word : String = ""
var index : Int
init(index: Int) {
self.index = index
}
}
I then have a view for a text field where the focus is controlled, I added a print statement here to see if word.index == focus!
is ever actually true
. It does become true
but setting the isFocused
has no impact and during the print it is still false
.
struct SolvedField: View {
@State var word: WordEntry
@FocusState var isFocused: Bool
@Binding var focus: Int?
var nextFocus: (Int) -> Void
var body: some View {
TextField("", text: $word.word)
.onChange(of: focus, perform: { newValue in
if(focus != nil){
self.isFocused = word.index == focus!
print("index \(word.index), focus \(focus!), isfocused: \(self.isFocused) should be focused \(word.index == focus!)")
}
})
.focused(self.$isFocused)
.submitLabel(.next)
.onSubmit {
isFocused = false
self.nextFocus(word.index)
}
}
}
and then a view which contains a list of word entries which are then shown as the text field control.
struct SolvedLettersLine: View {
@State var words = [WordEntry(index: 0), WordEntry(index: 1), WordEntry(index: 2), WordEntry(index: 3)]
@State var focus : Int?
var body: some View {
VStack(spacing:10){
Group{
ForEach(words) { word in
SolvedField(word: word, focus: $focus, nextFocus:{
focus = $0 + 1
})
}
}
}
}
}
Unfortunately I am completely stuck on how to get iOS to switch textfield focus to work, does anyone have an idea?
You should have just one @FocusState
in SolvedLettersLine
, that represents which field is currently focused. This should be of type Int?
.
You can now use the focused(_:equals:)
modifier to control the focus of text fields.
Then, you can pass this @FocusState
to SolvedField
as a FocusState.Binding
, similar to how you would pass a regular @State
to a @Binding
.
struct SolvedField: View {
// side note: word should not be a @State!
@Binding var word: WordEntry
@FocusState.Binding var focus: Int?
let nextFocus: () -> Void
var body: some View {
TextField("", text: $word.word)
.focused($focus, equals: word.index)
.submitLabel(.next)
.onSubmit {
nextFocus()
}
}
}
struct SolvedLettersLine: View {
@State var words = [WordEntry(index: 0), WordEntry(index: 1), WordEntry(index: 2), WordEntry(index: 3)]
@FocusState var focus: Int?
var body: some View {
VStack(spacing:10){
ForEach($words) { $word in
SolvedField(word: $word, focus: $focus) {
focus? += 1
}
}
}
}
}