如何防止列表项移除时NavigationLink自动返回
解决方案
首先明确问题根源:当device从devices数组移除时,绑定它的ForEach元素会被销毁,对应的NavigationLink也随之消失,导致导航自动返回。我们可以通过在进入详情页时暂停列表数据源的更新通知、离开时恢复的方式,阻止列表因数据源变化重新渲染,从而保留对应的NavigationLink。
1. 定义基础暂停型ObservableObject
先创建提供暂停/恢复更新能力的基础类:
import Combine class PausableObservableObject: ObservableObject { private var isPaused = false // 暂停更新通知 func pause() { isPaused = true } // 恢复更新并同步最新状态 func resume() { isPaused = false objectWillChange.send() } // 仅在非暂停状态下发更新通知 func publishWillUpdate() { if !isPaused { objectWillChange.send() } } }
2. 实现泛型封装类Pausable
创建泛型类封装任意类型的数据源,监听原数据源变化并在非暂停状态下同步更新:
class Pausable<T>: PausableObservableObject { @Published var value: T private var cancellable: AnyCancellable? init(initialValue: T, publisher: some Publisher<T, Never>) { self.value = initialValue super.init() // 订阅原数据源的变化 cancellable = publisher .sink { [weak self] newValue in guard let self = self else { return } self.value = newValue self.publishWillUpdate() } } }
3. 修改视图层逻辑
调整ContentView,用Pausable封装数据源
struct ContentView: View { @StateObject private var datasource = Datasource() @StateObject private var pausableDevices: Pausable<[Device]> init() { let initialDevices = datasource.devices _pausableDevices = StateObject(wrappedValue: Pausable(initialValue: initialDevices, publisher: datasource.$devices)) } var body: some View { NavigationView { DeviceList(pausableDevices: pausableDevices) .padding() .navigationTitle("Demo") .navigationBarTitleDisplayMode(.inline) } .navigationViewStyle(.stack) } }
修改DeviceList,控制暂停/恢复时机
struct DeviceList: View{ let pausableDevices: Pausable<[Device]> var body: some View{ if pausableDevices.value.isEmpty { Text("Scanning...") } else { ScrollView{ LazyVStack { ForEach(pausableDevices.value) { device in NavigationLink{ DetailView(device: device) // 进入详情页暂停更新 .onAppear { pausableDevices.pause() } // 离开详情页恢复更新 .onDisappear { pausableDevices.resume() } } label: { DeviceItem(device: device) } .buttonStyle(.plain) } } } } } }
关键说明
- 进入
DetailView时调用pause(),此时原datasource.devices变化不会触发列表重新渲染,对应的NavigationLink会被保留。 - 离开
DetailView时调用resume(),恢复更新并同步最新设备列表。 - 确保
Device类型遵循Identifiable协议,否则ForEach无法正确识别元素。
内容的提问来源于stack exchange,提问作者Ricky Mo
相关产品推荐
相关产品推荐

