Search code examples
iosswiftswiftuiswiftui-navigationlink

SwiftUI onTapGesture block NavigationLink action


I want to press a cell of List to display a menu then click the menu push to a new view by NavigationLink.

enter image description here

Here is my code:

import SwiftUI

struct ContentView: View {
    let array = ["a", "b"]

    @State var isPushed: Bool = false

    @State var isDisplayMenu: Bool = false
    @State var isDestination1Clicked: Bool = false
    var body: some View {
        NavigationView {
            List {
                ForEach(array, id:\.self) { value in
                    VStack {
                        RowView(title: value)
                         .frame(maxWidth: .infinity)
                        if isDisplayMenu {
                            HStack {
                                ZStack {
                                    Text("D1")
                                    NavigationLink(
                                        destination: Destination1(),
                                        label: {
                                            EmptyView()}).hidden()
                                }

                                ZStack {
                                    Text("D2")
                                    NavigationLink(
                                        destination: Destination2(),
                                        label: {
                                            EmptyView()}).hidden()
                                }
                            }

                        }
                    }
                    .background(Color.green)
                    .contentShape(Rectangle())
                    .onTapGesture(count: 1, perform: {
                        isDisplayMenu.toggle()
                    })
                }
            }
        }

    }
}

struct Destination1: View {
    var body: some View {
        Text("D1")
    }
}

struct Destination2: View {
    var body: some View {
        Text("D2")
    }
}

struct RowView: View {

    var title: String

    var body: some View {
        VStack {
            Text("title")
            Text(title)
        }.background(Color.red)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

When click the cell the D1 and D2 was displayed. But the NavigationLink doesn't work.

I think the reason is onTapGesture blocked it. How can I make the NavigationLink works?

Any help? thanks!


Solution

  • There are some restriction defined in List to be just a List itself.

    So that we cannot use more than one NavigationLink inside a List cell ( If we use more than one , we cannot get expected behaviour)

    And also Empty views does not get touch events.

    Here is the fixes for your code.

    struct ContentView: View {
        let array = ["a", "b"]
        
        @State var isPushed: Bool = false
        
        @State var isDisplayMenu: Bool = true
        @State var isDestination1Clicked: Bool = false
        var body: some View {
            NavigationView {
                ScrollView {
                    ForEach(array, id:\.self) { value in
                        VStack {
                            RowView(title: value)
                                .frame(maxWidth: .infinity)
                                .background(Color.green)
                                .onTapGesture(count: 1, perform: {
                                    withAnimation {
                                        isDisplayMenu.toggle()
                                    }
                                })
                            
                            if isDisplayMenu {
                                HStack {
                                    
                                    NavigationLink(
                                        destination: Destination1(),
                                        label: {
                                            Spacer()
                                            Text("D1")
                                                .foregroundColor(.black)
                                            Spacer()
                                        })
                                    
                                    NavigationLink(
                                        destination: Destination2(),
                                        label: {
                                            Spacer()
                                            Text("D2")
                                            Spacer()
                                        })
                                        .foregroundColor(.black)
                                    
                                }
                                .background(Color.purple)
                                
                            }
                        }
                        .padding()
                        .contentShape(Rectangle())
                        
                    }
                }
            }
            
        }
    }
    
    struct Destination1: View {
        var body: some View {
            Text("D1")
        }
    }
    
    struct Destination2: View {
        var body: some View {
            Text("D2")
        }
    }
    
    struct RowView: View {
        
        var title: String
        
        var body: some View {
            VStack {
                Text("title")
                Text(title)
            }.background(Color.red)
        }
    }
    
    struct ContentView_Previews: PreviewProvider {
        static var previews: some View {
            ContentView()
        }
    }