I am building an app for iOS and Mac Catalyst and have been able to code most of the
experience that I want except for functions that use swipe to delete in iOS.
The view includes multiple sections, each with a List and ForEach closure. I want to
be able to add the EditButton() function to the header of each section and have it
apply only to that section’s List.
I can
add an EditButton() function to gain this functionality, however,
so far I have only been able to make that work for the entire screen, not for the
individual sections.
I have tried refactoring the code for each section into functions and into structs
(as shown below). In all cases the EditButton() activates the delete icons for ALL
list rows, not just the section with the button.
I have also tried placing the EditButton() inside the section in the VStack. No difference.
Here’s a simple example with the latest code attempt:
struct ContentView: View {
@State private var selectedItem: String?
@State private var items = ["One", "Two", "Three", "Four", "Five"]
@State private var fruits = ["Apple", "Orange", "Pear", "Lemon", "Grape"]
var body: some View {
NavigationSplitView {
ItemSection(selectedItem: $selectedItem, items: $items)
FruitSection(selectedItem: $selectedItem, fruits: $fruits)
} detail: {
if let selectedItem {
ItemDetailView(selectedItem: selectedItem)
} else {
EmptyView()
}
}//nav
}//body
}//struct
struct ItemSection: View {
@Binding var selectedItem: String?
@Binding var items: [String]
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(items, id: .self) { item in
NavigationLink(value: item) {
Text(item)
}
}
.onDelete { items.remove(atOffsets: $0) }
}
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Items")
Spacer()
//uncomment when you have it working
//#if targetEnvironment(macCatalyst)
EditButton()
//#endif
}//h
.padding(.horizontal, 10)
}//section and header
}//body
}//item section
struct FruitSection: View {
@Binding var selectedItem: String?
@Binding var fruits: [String]
var body: some View {
Section {
VStack {
List(selection: $selectedItem) {
ForEach(fruits, id: .self) { fruit in
NavigationLink(value: fruit) {
Text(fruit)
}
}
.onDelete { fruits.remove(atOffsets: $0) }
}
.listStyle(PlainListStyle())
}//v
.padding()
} header: {
HStack {
Text("Section for Fruits")
Spacer()
}//h
.padding(.horizontal, 10)
}//section fruit
}//body
}//fruit section
struct ItemDetailView: View {
var selectedItem: String
var body: some View {
VStack {
Text(selectedItem)
Text("This is the DetailView")
}
}
}
Any guidance would be appreciated. Xcode 14.0.1 iOS 16
3
Answers
Here’s a more general & simplified approach using
PreferenceKey
:You use
EditingButton
instead ofEditButton
, & use.editMode()
at then end of yourView
. Then your sections become something like this:A more concise version of Timmy’s answer uses this reusable code:
Then the ItemSection is like this:
I have allowed drag and drop reordering to make it do what I was interested in as well.