I am iterating through an array of Contacts to display a cell for each contact in a grid. Please see my code:
ForEach($contacts, id: \.self) { $contact in
// Creating a grid item for each contact
ContactCell(contact: contact)
.navigationDestination(isPresented: $shouldPresentContactMainView) {
ContactMainView(contact: $contact)
}
.onTapGesture {
shouldPresentContactMainView.toggle()
}
}
What's weird is that, all of the grid items display the correct cell for each contact. However, when I tap on one of them, it segues, then displays the data of the last contact of the array... it doesn't matter if you tap on the first grid item, second, third, etc... all grid items will segue to the ContactMainScreen(with the same data here)
Why doesn't it send the data for the specific contact in the foreach loop?
You need a @State
for each cell so adding the navigationDestination
code to the ContactCell
can be one way of dong this.
struct ContactCell: View{
@Binding var contact: Contact
@State var isPresenting: Bool = false
var body: some View{
Text(contact.name)
.navigationDestination(isPresented: $isPresenting) {
ContactMainView(contact: $contact)
}
.onTapGesture {
isPresenting.toggle()
}
}
}
You can also use a ViewModifier
struct ContactsListView: View {
@State var contacts: [Contact] = (0...10).map { n in
Contact(name: "\(n)")
}
var body: some View {
LazyHGrid(rows: Array(repeating: .init(), count: 4)) {
ForEach($contacts, id: \.id) { $contact in
// Creating a grid item for each contact
ContactCell(contact: contact)
.modifier(PresentViewModifier(contact: $contact))
}
}
}
}
struct PresentViewModifier: ViewModifier{
@State var isPresenting: Bool = false
@Binding var contact: Contact
func body(content: Content) -> some View {
content
.navigationDestination(isPresented: $isPresenting, destination: {
ContactMainView(contact: $contact)
})
.onTapGesture {
isPresenting.toggle()
}
}
}