2

I have two NavigationLink in a cell of my List

I want to go to destination1 when I tap once,and go to destination2 when I tap twice. So I added two tap gesture to control the navigation.

But when I tap,there are two questions:

  • 1 The tap gesture block won't be called.
  • 2 The two navigation link will be both activated automatically even if they are behind a TextView. The real effect is: Tap the cell -> go to Destination1-> back to home -> go to Destination2 -> back to home

Here is my code :

struct MultiNavLink: View {
    @State var mb_isActive1 = false;
    @State var mb_isActive2 = false;
    
    var body: some View {
        return
            NavigationView {
                List {
                    ZStack {
                        NavigationLink("", destination: Text("Destination1"), isActive: $mb_isActive1)
                        NavigationLink("", destination: Text("Destination2"), isActive: $mb_isActive2)
                        Text("Single tap::go to destination1\nDouble tap,go to destination2")
                    }
                    .onTapGesture(count: 2, perform: {()->Void in
                        NSLog("Double tap::to destination2")
                        self.mb_isActive2 = true
                    }).onTapGesture(count: 1, perform: {()->Void in
                        NSLog("Single tap::to destination1")
                        self.mb_isActive1 = true
                    })
                }.navigationBarTitle("MultiNavLink",displayMode: .inline)
        }
    }
}

I have tried remove the List element,then everything goes as I expected. It seems to be the List element that makes everything strange.

I found this question:SwiftUI - Two buttons in a List,but the situation is different from me.

I am expecting for your answer,thank you very much...

Asperi
  • 228,894
  • 20
  • 464
  • 690
BinaryBang
  • 73
  • 7
  • I think your architecture is incorrect. Try removing the `ZStack` and `NavigationLink` from the `List` and replace with a `Button`, then apply the `.onTapGesture` modifiers to the `Button`, embedding the NavLinks in the `perform` code for each. – andrewbuilder Aug 20 '20 at 02:05

2 Answers2

5

Try the following approach - the idea is to hide links in background of visible content and make them inactive for UI, but activated programmatically.

Tested with Xcode 12 / iOS 14.

struct MultiNavLink: View {

    var body: some View {
        return
            NavigationView {
                List {
                    OneRowView()
                }.navigationBarTitle("MultiNavLink", displayMode: .inline)
        }
    }
}

struct OneRowView: View {
    @State var mb_isActive1 = false
    @State var mb_isActive2 = false

    var body: some View {
        ZStack {
            Text("Single tap::go to destination1\nDouble tap,go to destination2")
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .contentShape(Rectangle())
        .background(Group {
            NavigationLink(destination: Text("Destination1"), isActive: $mb_isActive1) {
                    EmptyView() }
                .buttonStyle(PlainButtonStyle())
            NavigationLink(destination: Text("Destination2"), isActive: $mb_isActive2) {
                    EmptyView() }
                .buttonStyle(PlainButtonStyle())
        }.disabled(true))
        .highPriorityGesture(TapGesture(count: 2).onEnded {
            self.mb_isActive2 = true
        })
        .onTapGesture(count: 1) {
            self.mb_isActive1 = true
        }
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • 1
    This solution perfectly meets my needs. At last,I find that when a list cell contains multi navigation links,you tap the cell once,all the navigation links will be activated. A key point is set them `disable(true)`,and active every single navigation link by other separately logic. – BinaryBang Aug 20 '20 at 05:57
  • @Asperi I'm convinced you are a genius – markusp Aug 25 '20 at 21:06
0

Navigation link has a initializer that takes a binding selection and whenever that selection is set to the value of the NavigationLink tag, the navigation link will trigger. As a tip, if the app can't differentiate and identify your taps, and even with two taps, still the action for one-tap will be triggered, then you can use a simultaneous gesture(.simultaneousGesture()) modifier instead of a normal gesture(.gesture()) modifier.

struct someViewName: View {
    
    @State var navigationLinkTriggererForTheFirstOne: Bool? = nil
    @State var navigationLinkTriggererForTheSecondOne: Bool? = nil
    
    var body: some View {
        VStack {
            NavigationLink(destination: SomeDestinationView(),
                           tag: true,
                           selection: $navigationLinkTriggererForTheFirstOne) {
                EmptyView()
            }
            
            NavigationLink(destination: AnotherDestinationView(),
                           tag: true,
                           selection: $navigationLinkTriggererForTheSecondOne) {
                EmptyView()
            }
            
            NavigationView {
                    Button("tap once to trigger the first navigation link.\ntap twice to trigger the second navigation link.") {
                        // tap once
                        self.navigationLinkTriggererForTheFirstOne = true
                    }
                    .simultaneousGesture(
                        TapGesture(count: 2)
                            .onEnded { _ in
                                self.navigationLinkTriggererForTheSecondOne = true
                            }
                    )
            }
        }
    }
}
Mahdi BM
  • 1,826
  • 13
  • 16
  • This element works well when I use it without list element. But when I put the element in a list, tapped it, and it also does not act as we expected. – BinaryBang Aug 20 '20 at 06:03