1

I'm trying to determine the destination of a NavigationLink of SwiftUI dynamically within init() based on the generic data provided to the view.

Based on the code below, if the Item is a Tour the destination should be a TourDetailView and otherwise a LocationDetailView.

struct CardView<Item: CardItem>: View {
  let card: Item
  private let destination: T
  
  init(card: Item) {
    self.card = card

    if Item.self == Tour.self {
      destination = TourDetailView(tour: card as! Tour) as! T
    } else {
      destination = LocationDetailView(location: card as! Location) as! T
    }
  }
  
  var body: some View {
    NavigationLink(destination: destination) {
      ...
    }
  }
}

Right now the code is not compiling because T isn't defined. If I define T as:

struct CardView<Item: CardItem, T: View>: View {

CardView is handled but then I have to edit the View calling the CardView which both introduces unnecessary complexity and eventually I have to define T in @main which is not allowed.

How can I achieve what I want? I tried to make destination another type but with no success.

Can
  • 4,516
  • 6
  • 28
  • 50
  • 1
    This topic should be helpful https://stackoverflow.com/questions/61304700/swiftui-how-to-avoid-navigation-hardcoded-into-the-view. – Asperi Jul 01 '21 at 04:15
  • The accepted answer solves ym problem. Actually, I tried `AnyView` before myself but was trying to stay away from it for a more elegant solution. Your sugegstion might help me. Thanks. @Asperi – Can Jul 01 '21 at 06:45

1 Answers1

1

Here is a simple demo to fix your issue.. just store the View in a property with type AnyView.

struct ContentView: View {
    let destination: AnyView

    init() {
      // This is just demo purpose, here comes your condition
      if false {
        destination = AnyView(DetailViewA())
      } else {
        destination = AnyView(DetailViewB())
      }
    }

    var body: some View {
        NavigationView {
            NavigationLink(
                destination: destination,
                label: {
                    Text("Navigate")
                })
        }
    }
}

struct DetailViewA: View {
    var body: some View {
        Text("A")
    }
}

struct DetailViewB: View {
    var body: some View {
        Text("B")
    }
}
davidev
  • 7,694
  • 5
  • 21
  • 56
  • I should've mentioned this in my question. I actually tried `AnyView` before. I wanted to stay away from it since I lose some type safety but I guess there it no other way. Appreciate it! @davidev – Can Jul 01 '21 at 06:46