SwiftUI:如何从Sheet跳转至新视图并推入导航栈
你猜的完全没错!Sheet属于独立于原NavigationView的视图层级,直接在Sheet里放置NavigationLink是不会触发跳转的——因为它没有属于自己的导航栈。下面给你一套完整的修复方案,同时优化整体的状态管理逻辑:
核心问题拆解
- Sheet是模态视图,不属于原ContentView的NavigationView导航栈,内部的
NavigationLink必须拥有自己的NavigationView才能生效 - 原先把
showSheet状态放在LessonButton里,状态分散,不利于后续功能扩展(比如需要在其他地方控制Sheet显示)
完整修复代码
import SwiftUI struct ContentView: View { // 将状态统一放在父视图管理,更符合SwiftUI数据流逻辑 @State private var selectedLesson: Lesson? @State private var showSheet = false let lessons = [Lesson(id:"1"), Lesson(id:"2"), Lesson(id:"3"), Lesson(id:"4"), Lesson(id:"5"), Lesson(id:"6"), Lesson(id:"7"), Lesson(id:"8"), Lesson(id:"9")] var body: some View { NavigationView { Form { List(lessons) { lesson in LessonButton(lesson: lesson) { // 点击按钮时,设置选中课程并触发Sheet显示 self.selectedLesson = lesson self.showSheet = true } } } .navigationTitle("课程列表") // 将Sheet绑定到父视图的状态变量 .sheet(isPresented: $showSheet) { // Sheet内部必须包裹独立的NavigationView,才能让NavigationLink生效 NavigationView { if let lesson = selectedLesson { LessonDetailView(lesson: lesson) } } } } } } // 简化LessonButton,仅负责触发点击回调 struct LessonButton: View { let lesson: Lesson let onTap: () -> Void var body: some View { Button(action: onTap) { Text(lesson.name) .frame(maxWidth: .infinity, alignment: .leading) } } } // 独立的课程详情视图 struct LessonDetailView: View { let lesson: Lesson var body: some View { VStack(spacing: 20) { Text("课程详情:\(lesson.name)") .font(.title) // 现在这个NavigationLink处于Sheet内部的NavigationView中,可以正常跳转 NavigationLink(destination: LessonStartView(lesson: lesson)) { Text("开始课程") .font(.headline) .padding() .background(Color.blue) .foregroundColor(.white) .cornerRadius(8) } } .navigationTitle(lesson.name) .navigationBarTitleDisplayMode(.inline) } } // 课程开始的全屏视图 struct LessonStartView: View { let lesson: Lesson var body: some View { VStack { Text("正在开始 \(lesson.name)") .font(.largeTitle) Text("课程内容加载中...") .foregroundColor(.gray) } .navigationTitle("课程进行中") } } struct Lesson: Identifiable { var id: String var name: String { "Lesson \(self.id)" } }
关键优化点说明
- 状态上移:把
selectedLesson和showSheet移到ContentView统一管理,符合SwiftUI单一数据源的设计原则 - Sheet内添加NavigationView:给Sheet的内容包裹一层
NavigationView,让内部的NavigationLink拥有可使用的导航栈 - 拆分视图职责:将课程详情、课程开始拆分为独立视图,代码结构更清晰,也方便后续功能扩展
- 回调式按钮:
LessonButton通过回调通知父视图处理点击事件,避免子视图持有不必要的状态
这样修改后,点击课程弹出详情Sheet,再点击"开始课程"就能正常跳转到全屏的课程视图了!
内容的提问来源于stack exchange,提问作者simibac
相关产品推荐
相关产品推荐

