Recently ran into an issue trying to perform Hero animation using matchedGeometryEffect in SwiftUI. My issue is that setting id for matchedGeometryEffect effect dynamically isn't working as expected.
This is what I have so far:
import SwiftUI struct HeroAnimationTest: View { let items: [Item] = [.init(id: 1), .init(id: 2), .init(id: 3), .init(id: 4)] @State var selectedItemInRowIndex: Int? = nil @Namespace var namespace var body: some View { List { ForEach(items, id: \.id) { item in ItemListRow(namespace: namespace, item: item) { tappedItem in withAnimation { selectedItemInRowIndex = tappedItem.id } } } .listRowSeparator(.hidden) .listRowBackground(Color.clear) .listRowInsets(EdgeInsets(h: 16, v: 8)) } .animation(.spring(), value: selectedItemInRowIndex) .scrollIndicators(.never) .listStyle(.plain) .overlay { if selectedItemInRowIndex != nil { largeGreen } } } var largeGreen: some View { ZStack { Color.black .onTapGesture { withAnimation { selectedItemInRowIndex = nil } } Color.green .frame(width: 200, height: 400) .matchedGeometryEffect(id: selectedItemInRowIndex, in: namespace) Text("ID -> \(selectedItemInRowIndex ?? 0)") } } } struct HeroAnimationTest_Previews: PreviewProvider { static var previews: some View { HeroAnimationTest() } } struct Item { let id: Int } struct ItemListRow: View { @State var enlargeElement = false let namespace: Namespace.ID let item: Item let onGreenTap: (Item) -> Void var body: some View { HStack { Text("ID -> \(item.id)") VStack { Color.green } .frame(width: 100, height: 40) .matchedGeometryEffect(id: item.id, in: namespace) .onTapGesture { onGreenTap(item) } VStack { Color.yellow } .frame(width: 100, height: 40) } } }
Current result:

I tried to hardcode id for largeGreen inside .matchedGeometryEffect(id: 3, in: namespace) to check if animation would work and it does:

Animation with hardcoded id is the expected result, but obviously it's only working for the 3rd row. Is it even possible to achieve this effect for green container in every row?
I'd really appreciate if anyone could take a look and give me some hint of what I'm missing here. I've been looking at this for a few hours now, but still can't figure out what went wrong.