iosswiftbuttonswiftuiswiftui-ontapgesture

NavigationLink open destination without isActive enabled


I have a NavigationLink with a simple text. Should open a secret logged-in page if determinated conditions are verified.

But I noticed that I can bypass the "isActive" with two simple tricks:

  1. long press on text and release, Secret view automatically loads
  2. press and drag the text, Secret view automatically loads

So I decided to implement and catch the longPress.
Implementing it, I solved the problem number 1, but the seconds still exist.

Here a video that explain better this issue: https://youtu.be/vuaT3lwUhLg

Here the simple snippet recorded in the video:

// the secret logged page
struct LoggedView: View {
    var body: some View {
        Text("secret view")
    }
}

// the example
struct ContentView: View {

    // loginSuccess is FALSE, so LoggedView() should not be called...
    @State var loginSuccess: Bool = false
    
    var body: some View {
        NavigationView {
            NavigationLink(destination: LoggedView(), isActive: $loginSuccess) {
                
                Text("LOGIN")
                    .background(Color.yellow)
                    .foregroundColor(.black)
                    .padding()
                    .onTapGesture(perform: {
                        // false, disabled to show the issue
                        loginSuccess = false
                    })
                    // if not implemented, longpress load the secret view
                    .onLongPressGesture {}
            }
        }
    }
}

What's wrong with it?
loginSuccess is never true, why this is ignored?

Is a wrong implementation (as I suppose) or is a swift bug?


Solution

  • I assume you just wanted to activate navigation programmatically, so you need active element like button or tappable view and hidden link.

    Here is possible solution for your code

    var body: some View {
        NavigationView {
                
            Text("LOGIN")                   // << activator !!
                .background(Color.yellow)
                .foregroundColor(.black)
                .padding()
                .onTapGesture(perform: {
                    // false, disabled to show the issue
                    loginSuccess = false
                })
                .background(
                   NavigationLink(destination: LoggedView(), isActive: $loginSuccess) {
                     EmptyView()      // << hidden !!
                })
        }
    }