Chris Dellinger
Chris Dellinger

Reputation: 2352

NavigationLink onTapGesture and navigation not firing consistently

In a SwiftUI view I implemented a vertically scrolling list by creating a VStack that contains a NavigationView that contains some text. I build this by looping through a popularFeedTypes object creating a NavigationLink for each item in the popularFeedTypes object. If a user clicks on the NavigationLink the user is pushed to a new view called FeedTypeView. You can see the code below.

VStack{
    NavigationView{
        List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
            NavigationLink(destination: FeedTypeView(feedType: feedType)) {
                Text(feedType.feedType)
            }.onTapGesture {
                print("TAPPED")
            }
        }
        .navigationBarTitle(Text("Discover"), displayMode: .inline)
    }
}

The problem I am experiencing is that if I have an onTapGesture action on the NavigationLink, I experience a different behavior from within the simulator depending upon how I click the row. If I click on the text or on the arrow (>) at the right hand side of the row, the onTapGesture fires off but no navigation occurs. If I click on the space between the text and the arrow, onTapGesture does not fire but navigation occurs. If I remove the onTapGesture code, clicking any of the three places causes navigation to occur. So my question is shouldn't navigation occur even with an onTapGesture action existing? Also shouldn't the onTapGesture action fire off regardless of where you click on the row that makes up the NavigationLink?

Upvotes: 10

Views: 12361

Answers (4)

Tariq
Tariq

Reputation: 9979

VStack {
    NavigationView{
        List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
            NavigationLink(destination: FeedTypeView(feedType: feedType)) {
                Text(feedType.feedType)
            }
            .simultaneousGesture(TapGesture().onEnded {
                print("TAPPED")
            })
            .buttonStyle(PlainButtonStyle())
        }
        .navigationBarTitle(Text("Discover"), displayMode: .inline)
    }
}

This should work. use simultaneousGesture on NavigationLink

Upvotes: 7

Victor Kushnerov
Victor Kushnerov

Reputation: 3964

You can use onAppear to handle tapped event.

VStack {
    NavigationView {
        List(self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
            NavigationLink(
                destination: FeedTypeView(feedType: feedType).onAppear { print("TAPPED") }) {
                Text(feedType.feedType)
            }
        }
        .navigationBarTitle(Text("Discover"), displayMode: .inline)
    }
}

Upvotes: 6

Mahdi BM
Mahdi BM

Reputation: 2094

If you want to do something before your navigation link is triggered, you can initialize a navigation link with tag and selection.

struct someViewName: View {
    
    @State var navigationLinkTriggerer: Bool? = nil
    @State var navigationLinkFeedType: FeedType
    
    var body: some View {
        VStack {
            NavigationLink(destination: FeedTypeView(feedType: navigationLinkFeedType),
                           tag: true,
                           selection: $navigationLinkTriggerer) {
                EmptyView()
            }
            
            NavigationView {
                List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
                    Button(feedType) {
                        // do all you want here
                        print("TAPPED")
                        // then set the navigationLinkTriggerer to value of you navigation link `tag`
                        // in this case tag is equal to `true`
                        // this will trigger the navigation link
                        self.navigationLinkFeedType = feedType
                        self.navigationLinkTriggerer = true
                    }
                }
                .navigationBarTitle(Text("Discover"), displayMode: .inline)
            }
        }
    }
}

Upvotes: 0

Anton
Anton

Reputation: 117

If you want to perform both action and navigation simultaneously you can do this:

VStack{
        NavigationView{
            List (self.popularFeedTypes.popularFeedTypes!, id: \.self) { feedType in
                NavigationLink(destination: FeedTypeView(feedType: feedType)) {
                    Text(feedType.feedType)
                }
                .simultaneousGesture(TapGesture().onEnded{
                    print("TAPPED")
                })
            }
            .navigationBarTitle(Text("Discover"), displayMode: .inline)
        }
    }

Upvotes: 2

Related Questions