SwiftUI:删除条目后如何在NavigationStack跳转回根视图?
解决SwiftUI删除条目后返回列表而非详情页的问题
你的问题根源在于:删除条目后,ThingsView中的selectedThing仍然指向已被删除的对象,导致详情栏停留在ThingView;同时EditView里的dismiss()只是回退到上一级(也就是详情页),并没有触发列表侧的状态更新。
以下是具体的修改方案:
步骤1:给ThingView添加删除回调闭包
修改ThingView,新增一个用于通知父视图删除完成的闭包参数,并传递给EditView:
struct ThingView: View { @Environment(\.modelContext) private var modelContext var thing: Thing var onDelete: () -> Void // 新增回调闭包 var body: some View { ScrollView { // 原有布局代码 } .navigationTitle(thing.fullName()) .navigationBarTitleDisplayMode(.large) .toolbar { ToolbarItemGroup(placement: .navigationBarTrailing) { NavigationLink { // 将回调传递给EditView EditView(thing: thing, onDelete: onDelete) } label: { Label("Edit", systemImage: "square.and.pencil") } .frame(width: 16, height: 16) } } } }
步骤2:修改EditView,添加回调并在删除时触发
在EditView中接收回调闭包,删除条目后调用它来清除父视图的选中状态,同时补上缺失的@State var showConfirmation = false:
struct EditView: View { @Environment(\.modelContext) private var modelContext @Environment(\.dismiss) private var dismiss @State var thing: Thing? var onDelete: (() -> Void)? // 新增可选回调 @State private var showConfirmation = false // 补上缺失的状态变量 var body: some View { let textfieldPadding = EdgeInsets(top: 4, leading: 0, bottom: 4, trailing: 0) Form { if let thing = thing { VStack(alignment: .center) { Button(role: .destructive) { showConfirmation = true } label: { HStack { Image(systemName: "trash") Text("Delete") } } .controlSize(.extraLarge) .confirmationDialog("Are you sure?", isPresented: $showConfirmation, titleVisibility: .hidden) { Button("Delete thing", role: .destructive, action: { modelContext.delete(thing) // 确保删除操作持久化 do { try modelContext.save() } catch { print(error.localizedDescription) } onDelete?() // 触发回调,清除父视图的选中状态 dismiss() // 关闭EditView }) } message: { Text("Deleting a thing will delete all data. It cannot be undone.") } } .frame(maxWidth: .infinity) } } .navigationBarTitleDisplayMode(.large) .navigationTitle(thing == nil ? "New thing" : "Edit thing") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Save") { saveThing() } } } } private func saveThing() { do { try modelContext.save() } catch { print(error.localizedDescription) } dismiss() } }
步骤3:在ThingsView中传递回调
修改ThingsView的详情栏部分,传递清除selectedThing的闭包:
struct ThingsView: View { @Environment(\.modelContext) private var modelContext @Query(sort: [SortDescriptor(\Thing.name)]) private var things: [Thing] @State private var selectedThing: Thing? @State private var columnVisibility: NavigationSplitViewVisibility = .doubleColumn var body: some View { NavigationSplitView(columnVisibility: $columnVisibility) { List(things, selection: $selectedThing) { thing in NavigationLink { ThingView(thing: thing, onDelete: { selectedThing = nil // 删除后清除选中状态 }) } label: { ThingRow(thing: thing) } } .listStyle(.plain) .toolbar { ToolbarItem { NavigationLink { EditView(thing: nil) } label: { Label("Add thing", systemImage: "plus") } } } .navigationTitle("My things") .navigationBarTitleDisplayMode(.large) } detail: { NavigationStack { if let selectedThing = selectedThing { ThingView(thing: selectedThing, onDelete: { selectedThing = nil // 删除后清除选中状态 }) .navigationBarTitleDisplayMode(.large) } else { Text("Please select a thing from the list or add a new one.") .navigationBarTitleDisplayMode(.large) } } } .navigationSplitViewStyle(.balanced) } }
关键说明
- 清除
selectedThing后,NavigationSplitView的详情栏会自动切换到默认提示文本,同时列表的选中状态也会取消,实现了“返回列表”的预期效果。 - 原代码中
EditView的showConfirmation没有添加@State修饰符,这会导致确认弹窗无法正常触发,必须补上。 - 删除操作后记得调用
modelContext.save(),确保删除操作持久化到数据存储中。
内容的提问来源于stack exchange,提问作者margusholland
相关产品推荐
相关产品推荐

