-1

I was following the Apple tutorial for SwiftUI and in 'Interfacing with UIKit' they made us make a carousel of images (images of landmarks). When I tried to experiment with it I made it so that when you tap the Image it takes you to that Image's detail view. I also added a caption beneath the Images in the carousel and I wanted that caption to take you to a small write-up about that particular Landmark when tapped. However, only the caption took you to its destination whereas the Image didn't do anything (Although it does highlight when you press down on it).

I won't dump the exact code but I've made a simplified version which has the same setup and gets my point across. I'll add comments to make it less tedious to understand.

struct ContentView: View {
    @State var currentPage = 0  // Tracks page number of the Carousel.

    var body: some View {
        NavigationView {
            List {
                Carousel(currentPage: $currentPage)
                    .listRowInsets(EdgeInsets())

                Text("Page number: \(currentPage + 1)")  // Displays page number of Carousel.
            }
        }
    }
}
struct Carousel: View {
    @Binding var currentPage: Int

    var body: some View {
       VStack {
            PageView([Photo(), Photo()], currentPage: $currentPage)  // This is a view from the Apple Tutorial. I'll link it incase you want to check out the code for this.
                .equatable()  // This allows the Text which shows the page number to work. I've made the '==' operator to always return true for the sake of simplicity.
                .frame(height: 350)

            NavigationLink(destination: Text("Write-up about landmark")) {
                Text("\"Captions...\"")  // This changes in the real app depending on the page number. This NavigationLink always works and takes me to the correct page.
                    .font(.headline)
                    .padding(.bottom, 10)
            }
            .padding(.trailing)
        }
    }
}

struct Photo: View {
    var body: some View {
        NavigationLink(destination: Text("Landmark Detail")) {  // This NavigationLink doesn't work. It highlights when pressed down on, but doesn't take you anywhere.
            Image(systemName: "person")  // These are the respective landmarks in the real app.
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: UIScreen.screenWidth)  // Custom static property. It's equal to UIScreen.main.bounds.size.width
        }
    }
}

Link to the PageView struct: https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit#create-view-to-represent-a-uipageviewcontroller (section 3 step 3)
(Note: Since I'm tracking the currentPage variable in ContentView instead of PageView, the currentPage variable inside of PageView is a Binding instead of a State in my code)

If someone can explain how I can make the NavigationLink work please let me know. If you're too lazy to write the code you can just give an explanation of how to do it and I'll figure it out from there.

Thanks in advance!

rayaantaneja
  • 1,182
  • 7
  • 18

1 Answers1

0

That link goes into different view hierarchy so NavigationView does not see it. Here is possible solution (not tested - scratchy).

1) pass callback action inside Photo

struct Photo: View {
    let action: () -> Void
    var body: some View {
        Button(action: action) {
            Image(systemName: "person")
                .resizable()
                .aspectRatio(contentMode: .fill)
                .frame(width: UIScreen.screenWidth)
        }
    }
}

2) Inject callback action from Carousel into Photo

struct Carousel: View {
    @Binding var currentPage: Int

    @State private var photoActivated = false // for in-code activation
    var body: some View {
       VStack {
            PageView([Photo(action: activateLink), Photo(action: activateLink)], currentPage: $currentPage)  // This is a view from the Apple Tutorial. I'll link it incase you want to check out the code for this.
                .equatable()  // This allows the Text which shows the page number to work. I've made the '==' operator to always return true for the sake of simplicity.
                .frame(height: 350)
                .background(
                    // hidden, to be activated by injected action
                    NavigationLink(destination: Text("Landmark Detail \(currentPage)"),
                        isActive: $photoActivated) { EmptyView() })

            NavigationLink(destination: Text("Write-up about landmark")) {
                Text("\"Captions...\"")  // This changes in the real app depending on the page number. This NavigationLink always works and takes me to the correct page.
                    .font(.headline)
                    .padding(.bottom, 10)
            }
            .padding(.trailing)
        }
    }

    private func activateLink() {
        self.photoActivated.toggle()
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • I tried this solution out but unfortunately when I pressed the caption it opened both the Links back to back. Is there possibly a solution using `onTapGesture`? – rayaantaneja Jun 10 '20 at 06:25
  • @rayaantaneja, having several links in one row of List requires special handling - it was solved [in this topic](https://stackoverflow.com/questions/61188131/swiftui-mvvm-coordinator-router-navigationlink) – Asperi Jun 10 '20 at 06:28
  • Hey, thank you so much for your help it really means a lot! I managed to get it working by using `NavigationLink(destination:tag:selection:_)` and `onTapGesture`. I've been at it for a full day now so I'm extremely grateful that you helped me solve my problem. Thanks a ton! @Asperi – rayaantaneja Jun 10 '20 at 07:03