7

I'm presenting a List inside a modal. If I'm inside a NavigationView the EditButton its totally broken.

enter image description here

struct ContentView: View {
@State var showSheetView = false

var body: some View {
    NavigationView {
        Button(action: {
            self.showSheetView.toggle()
        }) {
            Image(systemName: "bell.circle.fill")
                .font(Font.system(.title))
        }
        .sheet(isPresented: $showSheetView) {
            SheetView()
        }
    }
}
}

struct SheetView: View {
@State private var myArray: [String] = ["One", "Two", "Three"]
var body: some View {
    NavigationView {
        VStack {
            List {
                ForEach(myArray, id: \.self) { item in
                    Text(item)
                }.onDelete(perform: { indexSet in
                })
            }
        }
        .navigationBarItems(trailing: EditButton())
    }
}
}

If I remove the NavigationView where i present from, then at first it seems to work, the second time i present it gets broken again.

struct ContentView: View {
@State var showSheetView = false

var body: some View {
        Button(action: {
            self.showSheetView.toggle()
        }) {
            Image(systemName: "bell.circle.fill")
                .font(Font.system(.title))
        }
        .sheet(isPresented: $showSheetView) {
            SheetView()
        }
}
}

enter image description here

10
  • Can you describe what you think is broken and what desired effect is. Both movies look about the same. Commented Oct 18, 2020 at 20:01
  • So I expect when tapping edit button to enter edit mode. That means the red buttons for each row appears. Makes sense ? Commented Oct 18, 2020 at 20:15
  • Look on the second image, the appear the first time I present modally the screen. Commented Oct 18, 2020 at 20:16
  • What happens if you associate the edit button with the list instead of the vstack? Commented Oct 18, 2020 at 22:16
  • The same bug... Commented Oct 19, 2020 at 4:32

3 Answers 3

7

Manually handling the editMode works for me on macOS Big Sur with Xcode 12.1 / iOS 14.1.

I also had a problem of EditButton showing "Edit" again in an edit mode when I rotate the simulator, and the below solution solves it as well.

The following solution uses a custom EditButton struct that handles a manual editMode binding. First the custom EditButton:

struct EditButton: View {
    @Binding var editMode: EditMode

    var body: some View {
        Button {
            switch editMode {
            case .active: editMode = .inactive
            case .inactive: editMode = .active
            default: break
            }
        } label: {
            if let isEditing = editMode.isEditing, isEditing {
                Text("Done")
            } else {
                Text("Edit")
            }
        }
    }
}

Using the above EditButton is straightforward:

struct SheetView: View {
    @State private var myArray: [String] = ["One", "Two", "Three"]
    @State private var editMode = EditMode.inactive

    var body: some View {
        NavigationView {
            VStack {
                List {
                    ForEach(myArray, id: \.self) { item in
                        Text(item)
                    }.onDelete(perform: { indexSet in
                    })
                }
            }
            .navigationBarItems(trailing: EditButton(editMode: $editMode))
            .environment(\.editMode, $editMode)
            .animation(.spring(response: 0))
        }
    }
}

The EditButton in the trailing navigation bar item handles the @State private var editMode kept in SheetView. This editMode is then injected into the inner views using the environment .environment(\.editMode, $editMode). For the animation effect of the edit mode transition, I found .spring(response: 0) most appropriate.

Sign up to request clarification or add additional context in comments.

Comments

4

Instead of

.navigationBarItems(trailing: EditButton())

you could try:

.toolbar { EditButton() }

I had the same problem and this worked fine for me.

1 Comment

It works for me, but it is weird, isn't it?
0

This worked for me, in iOS 16.0

struct MyEditButton: View {
  
  @Binding var editMode: EditMode
  
  var body: some View {
    Button {
      switch editMode {
      case .active: editMode = .inactive
      case .inactive: editMode = .active
      default: break
      }
    } label: {
      if let isEditing = editMode.isEditing, isEditing {
        Text("Done")
      } else {
        Text("Edit")
      }
    }
  }
}

struct ContentView: View {
  
  @State var editMode: EditMode = .inactive
  
  @State var list = ["A", "B", "C"]
  
  var body: some View {
    Form {
      Section(header: HStack {
        MyEditButton(editMode: $editMode)
          .frame(maxWidth: .infinity, alignment: .trailing)
          .overlay(Text("LIST"), alignment: .leading)
      }) {
        List {
          ForEach(list, id: \.self) { value in
            Text(value)
          }
          .onDelete(perform: deleteSection)
          .onMove(perform: moveSection)
        }
      }
    }
    .environment(\.editMode, $editMode)
    .padding()
  }
  
  func deleteSection(at offsets: IndexSet) {
    list.remove(atOffsets: offsets)
  }
  
  func moveSection(from source: IndexSet, to destination: Int) {
    list.move(fromOffsets: source, toOffset: destination)
  }
}

enter image description here

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.