SwiftUI NavigationView在iOS 15下push页面后立即自动pop的问题求解
问题原因
这是iOS 15版本中SwiftUI的已知兼容性缺陷,本质是List的Cell复用逻辑和NavigationLink的状态判定规则在系统升级后发生了未公示的变更:ForEach循环生成的NavigationLink绑定的状态在页面push完成后会被List的刷新动作误重置,进而触发自动pop。该问题仅在iOS 15+系统版本上复现,iOS 14及更低版本不受影响。
可落地的修复方案
方案1:新增isDetailLink修饰符(优先推荐,侵入性最低)
直接给循环内的NavigationLink添加.isDetailLink(false)修饰符即可解决绝大多数场景下的问题,修改后的代码如下:
List { ForEach(dataToPopulateListFrom, id: \.id) { data in NavigationLink(destination: SomeView() .environmentObject(someEnviorementObject) .navigationBarTitle("", displayMode: .inline)) { SomeOtherView() } .isDetailLink(false) // 新增该行代码 } }
该方案对原有逻辑无任何副作用,适配横竖屏、分屏等所有常规使用场景。
方案2:替换List为ScrollView+VStack(适合列表数据量较小的场景)
如果方案1未生效,可通过避开List的复用逻辑解决问题,将外层List替换为ScrollView嵌套VStack即可,可按需添加分割线、点击效果模拟List的交互体验:
ScrollView { VStack(spacing: 0) { ForEach(dataToPopulateListFrom, id: \.id) { data in NavigationLink(destination: SomeView() .environmentObject(someEnviorementObject) .navigationBarTitle("", displayMode: .inline)) { SomeOtherView() .padding() } Divider() } } }
方案3:手动管理NavigationLink激活状态(最稳定,适合复杂场景)
如果列表有频繁刷新、动态增删元素的需求,可改用绑定激活状态的NavigationLink实现,完全脱离List的状态判定逻辑:
首先定义选中状态变量:
// 替换为你业务数据id的实际类型,如Int、UUID等 @State private var selectedItemId: String?
修改列表实现:
List { ForEach(dataToPopulateListFrom, id: \.id) { data in Button { selectedItemId = data.id } label: { SomeOtherView() } } } .background( NavigationLink(isActive: Binding( get: { selectedItemId != nil }, set: { if !$0 { selectedItemId = nil } } ), destination: { if let id = selectedItemId, let targetData = dataToPopulateListFrom.first(where: { $0.id == id }) { // 可按需将targetData传入目标页 SomeView() .environmentObject(someEnviorementObject) .navigationBarTitle("", displayMode: .inline) } }, label: { EmptyView() }) )
内容的提问来源于stack exchange,提问作者cseh_17
相关产品推荐
相关产品推荐

