iOS 16中如何无需显式创建Link,通过NavigationStack实现自动导航?
问题分析
你遇到的问题是使用navigationDestination(isPresented:)触发导航后,视图又跳回启动动画。核心原因是你在完成API调用后同时修改了doneLoading和show两个状态变量:当doneLoading触发导航时,show被设为false导致根视图重新显示启动动画,SwiftUI的NavigationStack在这种快速状态变化下出现了导航逻辑异常。
正确实现方法
方法1:使用NavigationPath管理导航(推荐)
NavigationPath是SwiftUI中更可靠的导航管理方式,能避免isPresented绑定可能出现的状态冲突问题:
@State var show = false @StateObject var viewModel: BumperScreenViewModel @StateObject var sheetManager = SheetManager() @State private var navigationPath = NavigationPath() // 新增导航路径 init(viewModel: @autoclosure @escaping () -> BumperScreenViewModel) { self._viewModel = .init(wrappedValue: viewModel()) } var body: some View { NavigationStack(path: $navigationPath) { // 绑定NavigationPath VStack { ZStack { Color(.trulliGold) .ignoresSafeArea() VStack { if show { Spacer() loadAnimation .frame(width: 150, height: 150) .task { try? await viewModel.getDataFromAPI() try? await Task.sleep(for: Duration.seconds(1)) navigationPath.append(()) // 添加路径元素触发导航 print("Done") } Spacer() } else { launchAnimation } } } } .navigationDestination(for: Void.self) { // 匹配路径元素类型 ContentView() .environmentObject(sheetManager) } } }
方法2:调整状态更新逻辑
如果坚持使用isPresented绑定,只需移除对show的修改,确保导航触发后根视图不会切换回启动动画:
修改task部分的代码:
.task { try? await viewModel.getDataFromAPI() try? await Task.sleep(for: Duration.seconds(1)) doneLoading = true // 仅设置导航触发状态,不修改show print("Done") }
保持navigationDestination的绑定逻辑不变:
NavigationStack { // ... 原有视图代码 ... } .navigationDestination(isPresented: $doneLoading) { ContentView() .environmentObject(sheetManager) }
这样修改后,当doneLoading变为true时,NavigationStack会正确将ContentView推到栈顶,原加载动画视图会被隐藏,不会再跳回启动动画。
内容的提问来源于stack exchange,提问作者kenada97
相关产品推荐
相关产品推荐

