iOS15+ SwiftUI Coordinator导航异常问题求助
iOS15+ SwiftUI导航栈Coordinator跳转异常修复方案
问题原因
你当前的代码使用单个selection变量控制所有NavigationLink,导致跳转到第三个视图时,根视图的NavigationLink因selection值不再匹配自身tag,触发自动dismiss,直接回到根页面。
因为NavigationLink的tag-selection机制是:当selection等于tag时激活跳转;当selection不等于tag时,若已跳转则自动关闭该链路,这就导致了跨层级跳转时的栈重置问题。
修复方案
改用导航路径数组管理导航状态,让每个NavigationLink独立控制自身的激活状态,避免全局变量冲突。这种方案完全兼容iOS15,同时具备良好的扩展性。
修改后的完整代码
import SwiftUI import Combine final class FlowCoordinator: ObservableObject { // 用数组维护导航路径,记录当前栈中的页面tag @Published var navigationPath: [String] = [] private var cancellables = Set<AnyCancellable>() init() { addObserver() } // 推入新页面 func push(_ viewTag: String) { navigationPath.append(viewTag) } // 返回上一页 func pop() { if !navigationPath.isEmpty { navigationPath.removeLast() } } // 返回根页面 func popToRoot() { navigationPath.removeAll() } private func addObserver() { $navigationPath .sink { path in print("当前导航路径: \(path)") } .store(in: &cancellables) } } struct ContentView: View { @StateObject var coordinator = FlowCoordinator() var body: some View { NavigationView { MainListScreen() .navigationTitle("Main List") } .environmentObject(coordinator) .navigationViewStyle(StackNavigationViewStyle()) } } struct MainListScreen: View { @EnvironmentObject var coordinator: FlowCoordinator var body: some View { VStack { NavigationLink( destination: MealDetailsScreen(), // 绑定激活状态:路径包含当前页面的目标tag时激活 isActive: .init( get: { coordinator.navigationPath.contains("MealDetailsScreen") }, set: { newValue in // 返回时从路径中移除对应tag if !newValue { coordinator.pop() } } ) ) { EmptyView() } Button(action: { coordinator.push("MealDetailsScreen") }) { Text("Go to Meal Details") } } } } struct MealDetailsScreen: View { @EnvironmentObject var coordinator: FlowCoordinator var body: some View { VStack { NavigationLink( destination: MealMultimediaScreen(), isActive: .init( get: { coordinator.navigationPath.contains("MealMultimediaScreen") }, set: { newValue in if !newValue { coordinator.pop() } } ) ) { EmptyView() } Button(action: { coordinator.push("MealMultimediaScreen") }) { Text("Go to Meal Multimedia") } } .navigationTitle("Meal Details") } } struct MealMultimediaScreen: View { @EnvironmentObject var coordinator: FlowCoordinator var body: some View { VStack { NavigationLink( destination: Text("Last View"), isActive: .init( get: { coordinator.navigationPath.contains("Text") }, set: { newValue in if !newValue { coordinator.pop() } } ) ) { EmptyView() } Button(action: { coordinator.push("Text") }) { Text("Go to Text") } } .navigationTitle("Meal Multimedia") } } #Preview { ContentView() }
关键改动说明
- Coordinator状态管理:用
navigationPath数组替代单个selection变量,记录所有已推入的页面tag,清晰维护导航栈层级。 - NavigationLink激活逻辑:每个
NavigationLink通过isActive绑定到路径是否包含自身目标tag,避免全局变量冲突。 - 返回逻辑联动:当用户通过系统返回按钮返回时,自动调用
pop()方法更新路径数组,保持状态与UI一致。
内容的提问来源于stack exchange,提问作者Andres Paladines
相关产品推荐
相关产品推荐

