How to hide a swiftui ToolBarItem when List is in edit mode?

198 Views Asked by At

I have a simple List inside a navigation stack with a toolbar. The toolbar contains an edit button and a "Finished" button to dismiss the view. How do I hide the "Finished" button when the view is in edit mode?

In the code below, I'm trying to use the environment variable editMode. This does not currently work correctly. It correctly hides the "Finished" button when I first press "edit" but it does not correctly reshow the button when I press "done". Also, pressing "edit" does not immediately switch to edit mode--it now takes two taps on the button to enter edit mode.

How do I correct this so that "done" returns when not editing and so that I only need press edit once to enter edit mode?

import SwiftUI

struct TestView: View {
    @Environment(\.dismiss) var dismiss
    @Environment(\.editMode) private var editMode
    @State var tests:Array<String> = ["A","B","C"]
    
    var body: some View {
        NavigationStack{
            List{
                Section("Recent"){
                    ForEach(tests, id:\.self){ test in
                        Text(test)
                    }
                    .onDelete{ indexes in
                        tests.remove(atOffsets: indexes)
                    }
                    .onMove{ source, destination in
                        tests.move(fromOffsets: source, toOffset: destination)
                    }
                    
                }
            }
                .navigationTitle("Test")
                .toolbar{
                    ToolbarItem(placement: .navigationBarLeading){
                        EditButton()
                    }
                    if editMode?.wrappedValue.isEditing == false{
                        ToolbarItem(placement: .navigationBarTrailing){
                            Button("Finished"){
                                dismiss()
                            }
                            
                        }
                    }
                }
        }

    }
}

#Preview {
    TestView()
}

1

There are 1 best solutions below

1
On BEST ANSWER

To ... hide the "Finished" button when the view is in edit mode..., you could try this approach, where you declare a isEditing var with a simultaneousGesture to toggle it and set the .environment(\.editMode,...) accordingly, as shown in the example code:

struct TestView: View {
    @Environment(\.dismiss) var dismiss
    @Environment(\.editMode) private var editMode
    @State var tests:Array<String> = ["A","B","C"]
    
    @State private var isEditing = false  // <-- here
    
    var body: some View {
        NavigationStack{
            List{
                Section("Recent"){
                    ForEach(tests, id:\.self){ test in
                        Text(test)
                    }
                    .onDelete{ indexes in
                        tests.remove(atOffsets: indexes)
                    }
                    .onMove{ source, destination in
                        tests.move(fromOffsets: source, toOffset: destination)
                    }
                }
            }
            .navigationTitle("Test")
            .toolbar {
                ToolbarItem(placement: .navigationBarLeading) {
                    EditButton()
                        .simultaneousGesture(TapGesture().onEnded {  // <-- here
                            isEditing.toggle()
                        })
                }
                if !isEditing {  // <-- here
                    ToolbarItem(placement: .navigationBarTrailing) {
                        Button("Finished"){
                            dismiss()
                        }
                    }
                }
            }
            .environment(\.editMode, .constant(isEditing ? .active : .inactive))  // <-- here
        }
    }
        
}