SwiftUI列表与导航状态管理异常:编辑子页面字段后自动返回父页面问题排查
问题原因及解决方案
我来帮你分析下这个问题哈——核心问题出在TestSettings的id实现上,以及ForEach的标识判断逻辑。
为什么编辑时会自动返回父页面?
你把TestSettings的id直接绑定到了name属性:
var id : String { self.name }
同时在父页面的ForEach里用了id: \.self来标识列表项。当你在子页面修改name时,TestSettings的id会跟着变化,而且因为TestSettings实现了Hashable,整个实例的哈希值也会改变。
SwiftUI的ForEach会通过标识判断列表项的存在状态:一旦某个项的标识(这里是self,也就是整个TestSettings实例)发生变化,它会认为原来的列表项被移除了,新的项被添加进来。这就导致原来触发导航的NavigationLink所在的行被销毁,导航栈也就自动弹出,回到了父页面。
怎么修复?
只需要把TestSettings的id改成独立于name的固定值,同时调整ForEach的写法即可:
1. 修改TestSettings的id实现
用UUID生成一个固定的、不随内容变化的id:
struct TestSettings : Identifiable, Hashable { let id = UUID() // 固定的UUID,不会随name修改而变化 var name : String }
这样即使修改name,每个TestSettings实例的标识也不会改变,ForEach能一直识别到它是同一个项。
2. 优化父页面的ForEach写法
因为TestSettings已经实现了Identifiable,你不需要手动指定id: \.self,直接使用绑定数组即可:
struct PickerTest: View { @State var settings : [TestSettings] var body: some View { NavigationView { List { ForEach($settings) { $thing in NavigationLink(destination: SecondLevel(things: $thing)) { Text(thing.name) // 可以显示实际的name,替代原来的"X" } } } .navigationTitle("Test") } } }
3. 子页面代码无需修改
你的SecondLevel页面用@Binding绑定数据的写法是正确的,修改后依然能直接更新原数组里的内容。
现在再测试一下:进入子页面编辑name时,页面不会自动返回,修改完成后返回父页面,列表里的内容也会同步更新。
内容的提问来源于stack exchange,提问作者Stephen Darlington
相关产品推荐
相关产品推荐

