Reputation: 153
I have a macOS SwiftUI application with several TextField
's laid out in a LazyHGrid
. They are in three columns, each with about 10 textfields. If there is only a single column tabbing through the TextField
's does the expected thing: it proceeds vertically down the list allowing the user to enter text in vertical order. However, if there are two or more columns, tabbing moves focus left-to-right, going across the entire row before moving to the next row.
I want the focus to move top-to-bottom, completing an entire column before moving to the next one. Does anyone know how to accomplish this? Nothing I've tried has worked so far.
Here is some code that shows the problem
import SwiftUI
struct ContentView: View {
@State private var input = [String](repeating: "", count: 4)
var body: some View {
let rows = [GridItem(.fixed(20), alignment: .leading),
GridItem(.fixed(20), alignment: .leading),
GridItem(.fixed(20), alignment: .leading),
]
LazyHGrid(rows: rows) {
Group {
Text("Column 1")
TextField("", text: $input[0])
TextField("", text: $input[1])
}.frame(width: 100)
Group {
Text("Column 2")
TextField("", text: $input[2])
TextField("", text: $input[3])
}.frame(width: 100)
}
}
}
Some things I've tried that didn't work:
LazyVGrid
instead. This has the same problem.TextField
's. This has no effect on focus order.focusScope
on the Group
's.Upvotes: 1
Views: 681
Reputation: 153
Okay, I found a way that sort of works. It doesn't work for my application because my application is too complicated and the compiler can't type check it when I use this approach. Hopefully this is something Apple will improve in future releases. But I'm posting the solution here in case anyone finds it useful. The reason I say it "sort of works" is because it doesn't respond properly to the tab key, only the enter key. This appears to be an Apple bug.
The basic idea is as follows
struct ContentView: View {
@State private var input = [String](repeating: "", count: 4)
@FocusState private var focus: Int?
var body: some View {
let rows = [GridItem(.fixed(20), alignment: .leading),
GridItem(.fixed(20), alignment: .leading),
GridItem(.fixed(20), alignment: .leading)
]
LazyHGrid(rows: rows) {
Group {
Text("Column 1")
TextField("", text: $input[0], onCommit: { updateFocus() })
.focused($focus, equals: 0)
TextField("", text: $input[1], onCommit: { updateFocus() })
.focused($focus, equals: 1)
}.frame(width: 100)
Group {
Text("Column 2")
TextField("", text: $input[2], onCommit: { updateFocus() })
.focused($focus, equals: 2)
TextField("", text: $input[3], onCommit: { updateFocus() })
.focused($focus, equals: 3)
}.frame(width: 100)
}
}
func updateFocus() {
if focus == nil {
focus = 0
} else {
focus = (focus! + 1) % 4
}
}
}
Upvotes: 1