You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI:如何从Sheet跳转至新视图并推入导航栈

解决SwiftUI中Sheet内NavigationLink无法工作的问题

你猜的完全没错!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)"
    }
}

关键优化点说明

  1. 状态上移:把selectedLesson和showSheet移到ContentView统一管理,符合SwiftUI单一数据源的设计原则
  2. Sheet内添加NavigationView:给Sheet的内容包裹一层NavigationView,让内部的NavigationLink拥有可使用的导航栈
  3. 拆分视图职责:将课程详情、课程开始拆分为独立视图,代码结构更清晰,也方便后续功能扩展
  4. 回调式按钮:LessonButton通过回调通知父视图处理点击事件,避免子视图持有不必要的状态

这样修改后,点击课程弹出详情Sheet,再点击"开始课程"就能正常跳转到全屏的课程视图了!

内容的提问来源于stack exchange,提问作者simibac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:30:24