SwiftUI Button as EditButton

The implementation below replaces EditButton's functionality with a Button:

import SwiftUI

struct ContentView: View {

    @State var isEditing = false
    @State var selection = Set<String>()

    var names = ["Karl", "Hans", "Faustao"]

    var body: some View {
        NavigationView {
            VStack {
                List(names, id: \.self, selection: $selection) { name in
                    Text(name)
                }
                .navigationBarTitle("Names")
                .environment(\.editMode, .constant(self.isEditing ? EditMode.active : EditMode.inactive)).animation(Animation.spring())
                Button(action: {
                    self.isEditing.toggle()
                }) {
                    Text(isEditing ? "Done" : "Edit")
                        .frame(width: 80, height: 40)
                }
                .background(Color.yellow)
            }
            .padding(.bottom)
        }
    }
}

#if DEBUG
struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
#endif

Result

result

However, by doing so, selection handling needs to be implemented by our own (which may or may not be an issue).

Unfortunately there isn't much documentation around that at this point: https://developer.apple.com/documentation/swiftui/list/3367016-init


There is a better way to do this in Beta 5, where you can grab the @Environment binding directly (also better to make this a navigation bar item):

import SwiftUI

struct EditableListView: View {

    @State var items: [String] = ["1", "2", "3"]
    @State var selections: Set<String> = []

    @Environment(\.editMode) private var editMode: Binding<EditMode>

    var body: some View {
        List(items, id: \.self, selection: $selections) { item in
            Text(item)
        }
        .navigationBarItems(trailing:
            Button(action: {
                self.editMode?.value.toggle()
            }) {
                Text(self.editMode?.value == .active ? "Done" : "Edit")
            }
        )
        .animation(.default)
    }
}

extension EditMode {

    mutating func toggle() {
        self = self == .active ? .inactive : .active
    }
}

EditableListAnimation


Here's a way to preserve EditButton's functionality while still observing changes.

EditButton()
    .simultaneousGesture(TapGesture().onEnded {
        // Do your thing
    })

This works for every view on which you want to observe taps.