You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何阻止文本光标每次输入时跳至末尾?

在SwiftUI NavigationStack中编辑TextField时光标跳至末尾的问题解决

问题原因

光标每次跳转至末尾的核心问题在于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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 05:30:53