SwiftUI EditMode and NavigationLink

Goal:


When in EditMode, the user can tap on the Row (ForEach NavigationLink) and push a different view to the navigation view stack.


How do I accomplish this?


UPDATED: Full code example


import SwiftUI
import PlaygroundSupport

struct DetailView: View {
    var body: some View {
        Text("Hello World")
    }
}

struct EditView: View {
    var body: some View {
        Text("Hello World")
    }
}


struct ContentView: View {
    @State var editMode: EditMode = .inactive
    
    var body: some View {
        NavigationView {
            List {
                Text("Testing EditMode")
                if self.editMode == .active {
                    NavigationLink(
                    destination: EditView()) {
                        Text("Go To Edit View")
                    }
                    .padding()
                } else {
                    NavigationLink(
                    destination: DetailView()) {
                        Text("Go To Detail View")
                    }
                    .padding()
                }
            }
            .navigationBarTitle("EditMode Problem")
            .navigationBarItems(trailing: EditButton())
            .environment(\.editMode, $editMode)
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())


1. This code is able to enable an EditButton, there is this weird animation between the two NavigationLink when the editMode state changes.


2. When editMode == .active, the row is not tapable. The goal is to enable the row to be tapable and enter a different view.

Replies

This is a SwiftUI question. Could you move the post to the right section of the forum.


How is EditView defined ?

Could you show the complete code so that we can test ?

Updated the original post with a full code example.

I'm also facing this issue in iOS 14.2.

Here's a simple example that is causing Buttons to not be tappable when edit mode is on:

Code Block swift
struct ContentView: View {
let items = ["A", "B", "C"]
@State private var selectedItem: String?
var body: some View {
List(selection: $selectedItem) {
Section(header: Text("Select an Item")) {
ForEach(items, id: \.self) { item in
Text(item)
}
}
Button("Next") {
print("You selected: \(selectedItem)")
}
}
.listStyle(InsetGroupedListStyle())
.environment(\.editMode, .constant(.active))
}
}


Trying to tap on the button will not print the string to on the console. As soon as I set the edit mode to .constant(.inactive), the button is tappable again and the print works.

I have tried replacing the the button with the following:
Code Block swift
Button("Next", action: {})
.onTapGesture {
print("You selected: \(selectedItem)")
}

But this hack only triggers the tap if it is exactly on the button text. Any tap in the remaining area of the list row will not trigger the onTapGesture. I'm not sure if this is an incorrect implementation of single selection lists on my side or if it's a bug in SwiftUI.

Solved the problem this way:


    var body: some View {
        NavigationView {
            List {
                ForEach(store.themes) { theme in
                        NavigationLink(destination: EmojiMemoryGameView(game: EmojiMemoryGame(theme))) {
                            VStack {
                                Text(theme.name)
                                Text(theme.emojiSet.joined())
                            }
                        }.gesture(editMode == .active ? tapGesture : nil)
                }
            }
            .environment(\.editMode, $editMode)
        }
    }

    var tapGesture: some Gesture  {
        TapGesture().onEnded{
            print("sucess")
        }
    }

Now if edit mode is inactive navigation link works like it should. If edit modi is active I assign custom gesture to this navigation link and it's works fine.

Have the same problem, as author of the post. Seems to me that NavigationLink is not working when editMode=.active. gesture helps to register tap on List item element, however, NavigationLink and transition to EditView still NOT handled as expected.

import SwiftUI
import PlaygroundSupport

struct DetailView: View {
    var body: some View { Text("Hello DetailView World") }
}

struct EditView: View {
    var body: some View { Text("Hello EditView World") }
}

struct ContentView: View {
    @State var editMode: EditMode = .inactive
    var body: some View {
        NavigationView {
            List {
                Text("Testing EditMode")
                ZStack {
                    if self.editMode == .active {
                        NavigationLink(destination: EditView()) {
                            Text("Go To Edit View")
                                .gesture(tapGesture)
                        }
                        .padding()
                    } else {
                        NavigationLink(destination: DetailView()) {
                            Text("Go To Detail View")
                        }
                        .padding()
                    }
                }
            }
            .navigationBarTitle("EditMode Problem")
            .navigationBarItems(trailing: EditButton())
            .environment(\.editMode, $editMode)
        }
    }

    var tapGesture: some Gesture  {
        TapGesture().onEnded{
            print("Tap In Go To Detail View")
        }
    }
}

PlaygroundPage.current.setLiveView(ContentView())

Hi ! has anyone figured out the solution for this issue ? (Moving to a different view while EditMode is active in NavigationLink )