在EditView中删除对象后返回至ItemsView的实现问题
SwiftUI 删除Item后同时关闭Sheet和DetailView问题
问题场景
我在大型应用中实现了一个简化的Item管理功能,包含三个视图:
- ItemsView:展示Item列表
- DetailView:展示选中的Item详情,提供编辑入口
- EditView:编辑Item文本或执行删除操作
目前的问题是:删除Item后调用dismiss()关闭EditView的sheet,回到DetailView时,虽然Item已经从ObservableObject的allItems数组中移除,但DetailView仍然显示已删除的Item。我需要实现点击删除按钮后,直接从EditView回到ItemsView,同时关闭sheet和DetailView。
原代码
struct Item: Identifiable, Hashable { var id = UUID().uuidString var title: String } class Items: ObservableObject { @Published var allItems = [ Item(title: "Apple"), Item(title: "Boat"), Item(title: "Car"), Item(title: "Drink") ] } struct ItemsView: View { @EnvironmentObject var items: Items var body: some View { NavigationStack { List { ForEach($items.allItems) { $item in NavigationLink { DetailView(item: $item) } label: { Text(item.title) } } } .navigationTitle("Items") } } } struct DetailView: View { @Binding var item: Item @Environment(\.dismiss) var dismiss @State private var isEditViewShowing = false var body: some View { VStack { Text(item.title) } .sheet(isPresented: $isEditViewShowing, content: { NavigationStack { EditView(item: $item) } }) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Edit") { isEditViewShowing = true } } } } } struct EditView: View { @EnvironmentObject var items: Items @Environment(\.dismiss) var dismiss @Binding var item: Item var body: some View { Form { TextField("New", text: $item.title) Button("Delete") { items.allItems.removeAll { $0.id == item.id } dismiss() } } .navigationTitle("Edit View") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Save") { dismiss() } } } } }
可行解决方案
方案1:用NavigationPath精准控制导航栈(推荐)
通过NavigationPath管理导航状态,删除Item后直接重置导航栈回到列表页:
- 修改
ItemsView,引入NavigationPath:
struct ItemsView: View { @EnvironmentObject var items: Items @State private var navigationPath = NavigationPath() var body: some View { NavigationStack(path: $navigationPath) { List { ForEach(items.allItems) { item in NavigationLink(value: item) { Text(item.title) } } } .navigationTitle("Items") .navigationDestination(for: Item.self) { item in // 检查Item是否存在,不存在则直接返回列表 guard let index = items.allItems.firstIndex(where: { $0.id == item.id }) else { navigationPath.removeLast() return EmptyView() } DetailView(item: $items.allItems[index], navigationPath: $navigationPath) } } } }
- 更新
DetailView,接收navigationPath绑定:
struct DetailView: View { @Binding var item: Item @Binding var navigationPath: NavigationPath @State private var isEditViewShowing = false var body: some View { VStack { Text(item.title) } .sheet(isPresented: $isEditViewShowing) { NavigationStack { EditView(item: $item, navigationPath: $navigationPath) } } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Edit") { isEditViewShowing = true } } } } }
- 修改
EditView,删除后同时关闭sheet并退回列表:
struct EditView: View { @EnvironmentObject var items: Items @Environment(\.dismiss) var dismiss @Binding var item: Item @Binding var navigationPath: NavigationPath var body: some View { Form { TextField("New", text: $item.title) Button("Delete") { items.allItems.removeAll { $0.id == item.id } dismiss() // 关闭EditView的sheet navigationPath.removeLast() // 从导航栈移除DetailView } } .navigationTitle("Edit View") .navigationBarTitleDisplayMode(.inline) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Save") { dismiss() } } } } }
方案2:在DetailView中监听Item状态自动返回
如果不想改动导航方式,可以在DetailView中监听allItems数组的变化,当Item被删除时自动返回列表:
修改DetailView:
struct DetailView: View { @Binding var item: Item @EnvironmentObject var items: Items @Environment(\.dismiss) var dismiss @State private var isEditViewShowing = false var body: some View { VStack { Text(item.title) } .sheet(isPresented: $isEditViewShowing) { NavigationStack { EditView(item: $item) } } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button("Edit") { isEditViewShowing = true } } } .onChange(of: items.allItems) { newItems in // 检查当前Item是否还在数组中 if !newItems.contains(where: { $0.id == item.id }) { dismiss() // 自动返回ItemsView } } } }
这种方案无需修改导航栈逻辑,仅通过监听数组变化实现自动返回,适合不想大幅改动原有代码的场景。
内容的提问来源于stack exchange,提问作者OxfordSi
相关产品推荐
相关产品推荐

