The .matchedGeometryEffect()
modifier makes it possible to identify multiple views as the same view, regardless of whether they are in the same place in the view hierarchy. This is useful because you can animate a view as it changes place in the view hierarchy. The parent hierarchy is given a @Namespace
and this can be passed to the modifier.
When using the modifier inside the animated views it is necessary to pass the namespace as a property so that it is accessible locally.
I am creating a grid of squares called AdaptiveView
that each display their index from 0 to 99. That means that they need to be given that index, and they need to be able to alter the currently selected index. This is because each one can be tapped once to bring it into focus and again to remove it from focus.
This selectedIndex value will start as -1, which is an invalid index. This is the state where the entire grid will be shown, while tapping an AdaptiveView
will change the selectedIndex
to the index for that view.
The colours are a rainbow that changes based on the index. The first 7 will use each of the colours in the array, and the 8th AdaptiveView
will then be red and each successive view will cycle through the colours one by one indefinitely.
Now I want to create the grid.
You may notice that each AdaptiveView
is only shown in the grid only when it isn’t currently selected.
Otherwise a Rectangle
will be shown, which is the primary font colour by default. In Light Mode this will be black, while in Dark Mode it will be white. The important thing is that it won’t be an AdaptiveView
, and the only place an AdaptiveView
with the same index will appear is in front of the grid as part of the ZStack
layout. As the view in the grid is set as the source of the animation, there is no conflict in situations where both views are rendered temporarily.
Here’s how it should look: