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

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)
    }
}

关键说明

  1. 清除selectedThing后,NavigationSplitView的详情栏会自动切换到默认提示文本,同时列表的选中状态也会取消,实现了“返回列表”的预期效果。
  2. 原代码中EditView的showConfirmation没有添加@State修饰符,这会导致确认弹窗无法正常触发,必须补上。
  3. 删除操作后记得调用modelContext.save(),确保删除操作持久化到数据存储中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 17:14:50