SwiftUI中如何检测视图真正被 Dismiss 的时机?
检测SwiftUI视图真正被Dismiss的时机
针对你在NavigationStack+NavigationSplitView场景下的需求,这里提供几个可靠的实现方式:
方案1:绑定NavigationPath+自定义路由状态监控
虽然NavigationPath内部值私有,但你可以维护一个和NavigationPath同步的自定义路由数组,通过对比数组变化判断视图是否被真正弹出。
示例代码:
class Router: ObservableObject { @Published var path = NavigationPath() // 自定义路由状态数组,存储每个视图的标识(比如枚举值) @Published var routeStack: [Route] = [] func push(_ route: Route) { path.append(route) routeStack.append(route) } func pop() { path.removeLast() routeStack.removeLast() } func popToRoot() { path.removeLast(path.count) routeStack.removeAll() } } // 定义路由枚举,标识不同视图 enum Route: Hashable { case menuItem1 case menuItem2 case detailView(id: Int) } // 使用时 struct ContentView: View { @StateObject private var router = Router() var body: some View { NavigationSplitView { List { Button("跳转菜单1") { router.push(.menuItem1) } Button("跳转菜单2") { router.push(.menuItem2) } } } detail: { NavigationStack(path: $router.path) { MapView() // 你的地图视图 .navigationDestination(for: Route.self) { route in switch route { case .menuItem1: MenuItem1View() .onChange(of: router.routeStack) { oldStack, newStack in // 检查当前视图是否从路由栈中被移除 if oldStack.contains(.menuItem1) && !newStack.contains(.menuItem1) { // 视图被真正dismiss,执行地图状态更新逻辑 updateMapState(for: .menuItem1, isActive: false) } } case .menuItem2: MenuItem2View() .onChange(of: router.routeStack) { oldStack, newStack in if oldStack.contains(.menuItem2) && !newStack.contains(.menuItem2) { updateMapState(for: .menuItem2, isActive: false) } } case .detailView(let id): DetailView(id: id) } } } } } private func updateMapState(for route: Route, isActive: Bool) { // 这里处理地图状态更新 } }
方案2:利用task(id:)修饰符监听视图生命周期
task(id:)会在视图出现时启动任务,当视图被真正dismiss(而非临时覆盖)时,任务会被自动取消。你可以在任务的onCancel回调中处理dismiss逻辑。
示例代码:
struct MenuItem1View: View { var onDismiss: () -> Void var body: some View { Text("菜单1视图") .task(id: UUID()) { // 用UUID确保每次视图初始化都创建新任务 await withTaskCancellationHandler { // 视图存在期间的逻辑(可选) } onCancel: { // 视图被真正dismiss时触发 onDismiss() } } } } // 在导航目标中使用 .navigationDestination(for: Route.self) { route in switch route { case .menuItem1: MenuItem1View { // 执行地图状态更新 updateMapState(for: .menuItem1, isActive: false) } // ...其他视图 } }
这个方案无需维护全局路由状态,每个视图自己处理dismiss回调,适合独立视图的场景。
内容的提问来源于stack exchange,提问作者Albin
相关产品推荐
相关产品推荐

