Custom button does not trigger editMode but EditButton does

I made a new project to figure out how List and editing List works and there was no problem at all, everything was going smoothly.
Then I transferred the code over into an existing project but I ran into an unusual problem: when I try to use custom button to change the EditMode and make List editable it does not work. However when I use the original EditButton the List goes into editing mode.
Do you have any ideas, why is this happening?
This is the code:
Code Block swift
@Environment(\.editMode) var editMode
var body: some View {
        VStack {
            HStack {
                Spacer()
                EditButton()
                    .accentColor(.black)                
                Button(action: {
                    editMode?.wrappedValue = editMode?.wrappedValue == .active ? .inactive : .active
                }) {
                    Text(editMode?.wrappedValue == .active ? "Saved" : "Modify")
                }
            }
            .padding(.horizontal)
            if emptyDictionary {
                Divider()
                Spacer()
                Text("Nothing here yet")
                    .font(.light18)
                Spacer()
            } else {
                List {
                    ForEach(keys, id:\.self) { color in
                        if !favourites(color: color).isEmpty {
                            Section(header: headerView(color: color)) {
                                ForEach(favourites(color: color)) { fav in
                                    versRow(vers: fav, color: color)
                                }
                                .onDelete(perform: {indexSet in
                                    store.deleteFavourites(color: color, indexSet: indexSet)
                                })
                                .onMove { (indexSet, newOffset) in
                                    store.moveFavourites(color: color, indexSet: indexSet, newOffset: newOffset)
                                }
                            }
                        }
                    }
                }
                .padding(.horizontal)
            }
        }
    }

The thing is the editMode environment variable changes with every click because the text in the custom button changes accordingly but the List does not go into editing mode. Strange.

Answered by OOPer in 638896022

Not a NavigationView but a TabView.

Thanks for clarifying. And I can confirm that the List does not go into edit mode using the custom button.

In a simplified project like mine, the same workaround found for NavigationView works.
Code Block
@State var editMode: EditMode = .inactive //<- Declare the @State var for editMode
var body: some View {
TabView {
Text("Dummy")
.tabItem {Text("1")}
//...
FavoritesView(dict: favoritesDict)
.tabItem {Text("2")}
.environment(\.editMode, $editMode) //<- And pass the binding explicitly
//...
}
}


Please try with your project.
It's hard to test your code as you are not showing many parts used in your code.
But if I fill such parts by guess, your custom button (showing Saved or Modify) turns the edit mode on/off.

Something in your hidden parts of your project is affecting. Please find that.
This is a pure View, I just did not add the struct declaration, the closing brackets and the other child Views. Nothing more.
And the button is just a custom EditButton. This solution is pretty common in SwiftUI, because the original EditButton is not really customizable, there's no way of changing the text according the EditMode. I just put the native EditButton next to it for testing.

The interesting part, and my real question is that the native EditButton changes the EditMode i.e puts the List in editable mode, while the custom button, which is supposed to change the same EditMode does not do it.

while the custom button, which is supposed to change the same EditMode does not do it.

As I have already written, the custom button in my project does change the EditMode.

Please show enough code to reproduce the issue.

If there is some other conditions to reproduce the issue, please provide all such info.
Code Block
struct FavoritesView: View {
var dict: [String: [Vers]]
    @Environment(\.editMode) var editMode
    var body: some View {
        VStack {
            HStack {
                Spacer()
                Text("Favs")
                    .font(.medium16)
                Spacer()
                EditButton()
                    .accentColor(.black)                
                Button(action: {
                    editMode?.wrappedValue = editMode?.wrappedValue == .active ? .inactive : .active
                }) {
                    Text(editMode?.wrappedValue == .active ? "Save" : "Modify")
                }
            }
            .padding(.horizontal)
            if emptyDictionary {
                Divider()
                Spacer()
                Text("Nothing here yet")
                    .font(.light18)
                Spacer()
            } else {
                List {
                    ForEach(Array(dict.keys), id:\.self) { color in
                        if !(dict[color] ?? []).isEmpty {
                            Section(header: Text(color)) {
                                ForEach(dict[color] ?? [], id:\.self) { fav in
                                    Text(dict[color].title)
                                }
                                .onDelete(perform: {indexSet in
                                    print(indexSet)
                                })
                                .onMove { (indexSet, newOffset) in
                                    print(indexSet, newOffset)
                                }
                            }
                        }
                    }
                }
                .padding(.horizontal)
            }
        }
    }

The custom button changes the EditMode indeed but the List never goes into edit mode. Only with the EditButton.
And I use Xcode 12.
Thanks for showing your updated code. But your new code does not compile, even if I filled definitions for Vers, emptyDictionary, medium16 and light18.

The line 32 should be something like Text(fav.title), no?
With changing the line as above, I could compile the code and the custom button does change the EditMode.

the List never goes into edit mode.

Can you clarify how you are checking it? In my project, with tapping the custom button, a delete icon (red-circled -) and a dragging nob (-like icon) appears in each row of the cell and each cell becomes draggable.

What else is needed for your edit mode?


One more thing to clarify.

Does your FavoritesView exist in a NavigationView?
Thank you for checking it for me. This is exactly I want: draggable rows and the delete icon in front of each the row.
But nothing happens. The text in the custom button changes according to the EditMode but the List just sits there, no reaction whatsoever.
I know there's nothing wrong in the code, because in another case it works like a charm. I just thought someone ran into similar problem when one case works the other doesn't.
Thanks again.
Thanks for your reply.

I know there's nothing wrong in the code

Yes, but there may be some condition to reproduce the same issue. As far as I tried, when I embed the view inside NavigationView, I could find the behavior you described.

If the condition is clarified, we may be able to find some workaround.

So, I ask you again, as you may be missing the last part of my reply added later, is FavoritesView shown in a NavigationView?
Oh, thank you for finding it. Not a NavigationView but a TabView. And it does suppress the EditMode change caused by a custom button, I tried it out in my working example.
I just need to find a way to make it work.
Accepted Answer

Not a NavigationView but a TabView.

Thanks for clarifying. And I can confirm that the List does not go into edit mode using the custom button.

In a simplified project like mine, the same workaround found for NavigationView works.
Code Block
@State var editMode: EditMode = .inactive //<- Declare the @State var for editMode
var body: some View {
TabView {
Text("Dummy")
.tabItem {Text("1")}
//...
FavoritesView(dict: favoritesDict)
.tabItem {Text("2")}
.environment(\.editMode, $editMode) //<- And pass the binding explicitly
//...
}
}


Please try with your project.
Yes, it works! I needed to wrap the button action into a withAnimation closure to trigger the animation of editMode changing, but it is now what you're expecting from an EditButton.
Custom button does not trigger editMode but EditButton does
 
 
Q