SwiftUI中如何阻止文本光标每次输入时跳至末尾?
问题原因
光标每次跳转至末尾的核心问题在于navigationDestination闭包内的状态绑定逻辑:
- 当修改
records[index].string时,@State修饰的records数组会触发视图刷新,导致navigationDestination闭包重新执行。 - 每次闭包执行时,
index = records.firstIndex { $0.id == id }会被重新计算,这使得TextField的绑定$records[index].string被视为全新的绑定实例。 - SwiftUI会基于新的绑定重新初始化TextField的光标状态,最终强制光标跳转到文本末尾。
解决方案
方案一:将Record改为ObservableObject类
把Record重构为遵循ObservableObject的类,让单个记录的修改独立于数组整体刷新,保持绑定的稳定性:
struct CursorResetting: View { class Record: Identifiable, ObservableObject { @Published var string = "" let id = UUID() init(string: String) { self.string = string } } @State var path = NavigationPath() @State private var records = [ Record(string: "To be and not to be"), Record(string: "That begs the question") ] var body: some View { NavigationStack(path: $path) { Form { List { ForEach(records) { record in NavigationLink(value: record.id) { Text(record.string) } } } } .navigationDestination(for: UUID.self) { id in if let record = records.first(where: { $0.id == id }) { Form { TextField("Value", text: $record.string) } } else { Text("Invalid ID") } } } } }
方案二:直接传递记录的绑定
跳过ID查找索引的步骤,通过ForEach($records)直接获取每个记录的绑定,在导航目标视图中直接使用:
struct CursorResetting: View { struct Record: Identifiable { var string = "" let id = UUID() } @State var path = NavigationPath() @State private var records = [ Record(string: "To be and not to be"), Record(string: "That begs the question") ] var body: some View { NavigationStack { Form { List { ForEach($records) { $record in NavigationLink { Form { TextField("Value", text: $record.string) } } label: { Text(record.string) } } } } } } }
方案说明
- 方案一中,
Record作为ObservableObject,修改其string属性只会触发单个对象的视图更新,不会让整个records数组的标识变化,navigationDestination内的绑定始终稳定,光标状态得以保留。 - 方案二中,直接通过绑定传递记录,避免了反复查找索引的过程,绑定始终指向同一记录的属性,从根源上解决了绑定重建导致的光标重置问题。
内容的提问来源于stack exchange,提问作者Curious Jorge
相关产品推荐
相关产品推荐

