@jayelevy needs some help getting to a destination.
Can someone help me connect the dots?
thanks for any guidance
Thanks for posting code. This helps show where you may have not grasped the concepts.
@twoStraws has a nice video on this.
See -> Different Destinations
Using a standard NavigationLink
is just fine, if you have a small number of potential destinations. However, what is SwiftUI doing? For each and every tappable destination, SwiftUI is in the background building a destination view. If you have a hundred possible tappable items, SwiftUI will build that many destination views, even though your user will only tap one!
Efficient Code
Using the updated .navigationDestination
syntax is much more efficient. In the List
of tappable options, you'll provide what I call a data package. Then when you tap an item, SwiftUI determines the package's type
and selects an appropriate destination view and will pass in the data package for the new view to render.
This gives you flexibility (see code snip) because now you can have ONE List
that contains one or more TYPES of data packages. In the example below, the List
contains both Integer
and Wizard
types of data. You'll see a different destination based on the TYPE of data you tap.
An additional benefit is that SwiftUI now builds only ONE view, rather than (potentially) hundreds of views that may never be displayed.
struct Wizard: Identifiable, Equatable, Hashable {
static func == (lhs: Wizard, rhs: Wizard) -> Bool {
return lhs.name == rhs.name
}
var id = UUID().uuidString
var name: String // Student's name
var house: String // Sorting Hat
static var sampleStudents = [
Wizard(name: "Jay", house: "Hufflepuff" ),
Wizard(name: "Hermione", house: "Gryffindor" ),
Wizard(name: "Ron", house: "Gryffindor" ),
Wizard(name: "Luna", house: "Ravenclaw" )
]
}
struct WizardsListView: View {
@State private var wizards = [Wizard]()
var body: some View {
NavigationStack {
// Note! This list has four Wizard objects and two Integer objects.
// Goal: Go to different views based on object TYPE.
List {
// For each item in the LIST, provide a package of data, and its label.
ForEach(wizards) { wizard in
// Here's the package of data for a selected destination
NavigationLink( value: wizard ) {
// This is what you SEE in the selectable list
RowView(wizardName: wizard.name) // what to see in the list of tappable items
}.padding(.vertical)
}
// Provide a LABEL and a PACKAGE of DATA
NavigationLink("🧙🏾♂️ Random Integer", value: Int.random(in: 0..<50 )) // Note! the package is an Integer
NavigationLink("🧙🏾♂️ Random Integer", value: Int.random(in: 51..<100)) // Note the package type!
}
// ============= Based on the type of the PACKAGE, go to a different destination ===============
// IF a row is tapped, then build a destination view
// using the data package noted above
.navigationDestination(for: Wizard.self) { WizardView(theWizard: $0) }
.navigationDestination(for: Int.self ) { IntegerView(someInteger: $0) }
.navigationTitle("Wizards")
}
.onAppear{ wizards = Wizard.sampleStudents } // Populate with sample students
}
}
// This is row you see in the tappable LIST view
struct RowView: View {
var wizardName: String
var body: some View {
HStack {
Text("🧙🏾♂️").padding(.trailing); Text(wizardName)
}.font(.title)
}
}
// This is the destination for Wizards ========================== DESTINATION
struct WizardView: View {
var theWizard: Wizard // Object to display
var body: some View {
VStack(alignment: .leading) {
Text("🧙🏾♂️ \(theWizard.name)").font(.largeTitle)
Text(theWizard.house).font(.title3)
}.padding(50).background { Color.cyan.opacity(0.3) }
}
}
// This is the destination for Integers ======================== DESTINATION
struct IntegerView: View {
var someInteger: Int
var backgroundColor: Color { someInteger > 50 ? .cyan.opacity(0.4) : .indigo.opacity(0.4) }
var body: some View {
ZStack {
Rectangle().fill(backgroundColor).frame(width: 200, height: 200)
Text("\(someInteger)").font(.largeTitle)
}
}
}
Keep Coding!