I have a view called TitleList that allows the user to edit the title of a row using a .swipeAction (it will replace the NavigationLink with a TextField).
While a title is being edited, if a user taps another row's NavigationLink and a view gets pushed on the root views NavigationStack, when I return to the root view and try to edit the previous row again, its TextField doesn't automatically activate despite its FocusState property being set to true (I have to tap the field for the keyboard to pop up). Here is a video that shows what I'm describing and also here is the full code:
import SwiftUI
struct HomeView: View {
@State private var titles: [String] = ["Title 1", "Title 2", "Title 3"]
var body: some View {
NavigationStack {
VStack {
List {
TitleList(titles: $titles)
}
}
}
}
}
struct TitleList: View {
@Binding var titles: [String]
@State private var renamingTitleIndex: Int?
@State private var renamingTextFieldUserInput: String = ""
@FocusState private var renamingTextFieldIsFocused: Bool
var body: some View {
ForEach(Array(titles.enumerated()), id: \.offset) { index, title in
if renamingTitleIndex != index {
NavigationLink(destination: Text("Test")) {
Text(titles[index])
}
.swipeActions(allowsFullSwipe: false) {
Button {
renamingTextFieldIsFocused = true
renamingTitleIndex = index
renamingTextFieldUserInput = ""
} label: {
Label("Rename", systemImage: "pencil")
}
}
} else {
VStack {
TextField("", text: $renamingTextFieldUserInput)
.focused($renamingTextFieldIsFocused)
.onSubmit {
if !renamingTextFieldUserInput.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
titles[index] = renamingTextFieldUserInput
}
}
.onDisappear {
renamingTextFieldIsFocused = false
}
.onChange(of: renamingTextFieldIsFocused) { isFocused in
if !isFocused {
renamingTitleIndex = nil
renamingTextFieldUserInput = ""
}
}
}
}
}
}
}
Is there a way to get the FocusState property to work so I don't have manually tap the TextField when this happens? I know I could disable all the other rows while a row is editing (I probably will end up doing this regardless), but I'd also like to see if I can find a solution to this problem as I have other NavigationLinks in other Lists that could be triggered and would like to avoid having to disable all of them when a TitleList row is editing.
Add a delay when setting focus, this ensures the focus is set after the view is fully rendered.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
renamingTextFieldIsFocused = true
}