Working with MatchedGeometryEffect

In SwiftUI, MatchedGeometryEffect is a powerful modifier that allows you to create smooth, seamless animations. Learn more.
Working with MatchedGeometryEffect

In SwiftUI, MatchedGeometryEffect is a powerful modifier that allows you to create smooth, seamless animations when transitioning views between different states. It is particularly useful for animating changes in view hierarchy, position, size, and shape.

To use MatchedGeometryEffect, you need a Namespace. A Namespace is created using the @Namespace property wrapper, and it ensures that the identifier is unique within a specific scope.

	@Namespace var animation

Diving In

To start, we're going to animate a text and an icon from one view to another:


struct ContentView: View {

	@Namespace var animation
	@State var showDetails = false

    var body: some View {
			ZStack {
				if !showDetails {
					VStack {
						Image(systemName: "globe")
							.imageScale(.large)
							.foregroundStyle(.tint)
							.matchedGeometryEffect(id: "globe", in: animation)
						Text("Hello, world!")
							.font(.title)
							.frame(width: 150, height: 50)
							.matchedGeometryEffect(id: "text", in: animation)

					}
					.padding()
				} else {
					VStack {
						HStack {
							Image(systemName: "globe")
								.imageScale(.large)
								.foregroundStyle(.tint)
								.matchedGeometryEffect(id: "globe", in: animation)
							Text("Hello, world!")
								.font(.title)
								.frame(width: 150, height: 50)
								.matchedGeometryEffect(id: "text", in: animation)
						}
						Text("Long description to display when showing the details of Hello World! ")

					}
				}
			}
			.onTapGesture {
				withAnimation {
					showDetails.toggle()
				}
			}
    }
}

To match one element to another you need to use the same ID on both the first view and the second. As you can see we use fixed size here for the Text Element. We could use autolayout for this but it results in some janky animation with truncated text, which we want to avoid. And using two different fonts requires using Animatable which we'll save for another time.

We can also add a background to our view and animate it:

struct ContentView: View {

	@Namespace var animation
	@State var showDetails = false

	var body: some View {
		ZStack {
			if !showDetails {
				VStack {
					Image(systemName: "globe")
						.imageScale(.large)
						.foregroundStyle(.tint)
						.matchedGeometryEffect(id: "globe", in: animation)
					Text("Hello, world!")
						.font(.title)
						.frame(width: 150, height: 50)
						.matchedGeometryEffect(id: "text", in: animation)
				}
				.padding()
				.background {
					Rectangle()
						.fill(.pink)
						.matchedGeometryEffect(id: "background", in: animation)
				}
			} else {
				VStack {
					HStack {
						Image(systemName: "globe")
							.imageScale(.large)
							.foregroundStyle(.tint)
							.matchedGeometryEffect(id: "globe", in: animation)
						Text("Hello, world!")
							.font(.title)
							.frame(width: 150, height: 50)
							.matchedGeometryEffect(id: "text", in: animation)
					}
					.padding()
					.background {
						Rectangle()
							.fill(.pink)
							.matchedGeometryEffect(id: "background", in: animation)
					}
					Text("Long description to display when showing the details of Hello World! ")

				}
			}
		}
		.onTapGesture {
			withAnimation {
				showDetails.toggle()
			}
		}
	}
}

If we want to animate the container of the view, then it's important to note that ZStack, VStack and HStack don't work well with matchedGeometryEffect, so we would need to first apply a modifier to the background of the view. As you can see it smoothly transitions between the small and large states.

In Review

MatchedGeometryEffect is a versatile and powerful tool for creating visually appealing animations. It can be particularly effective for complex view transitions and interactive UI elements, providing a smooth and intuitive user experience.

If you have questions on this modifier or if you need support building your product, contact Studio today.

Subscribe to Studio Bytes, your weekly blast of all things tech.

Great! You’ve successfully signed up.

Welcome back! You've successfully signed in.

You've successfully subscribed to Knowledge.

Success! Check your email for magic link to sign-in.

Success! Your billing info has been updated.

Your billing was not updated.