Easier SwiftUI animations with AnimatedState property wrapper.
Tags: swiftui, swift, animations
Published: 2021-06-01 09:41:26

To animate something SwiftUI you have a couple of choices, implicit and explicit animations. Implicit animations are done view view modifiers `.animation(.easeIn)` and explicitly ones are declare inside the animation block `withAnimation`.

I often use explicit animation and therefore I am always setting the values of a State property inside the animation block.

```swift
struct ExplicityAnimationExample: View {
	@State var scaleSquare = false
	var body: some View {
		Rectangle()
		.fill(Color.red)
		.frame(width: 100, height: 100)
		.scaleEffect(scaleSquare ? 2 : 1)
		.onAppear {
			withAnimation(.spring()) {
				scaleSquare.toggle()
			}
		}
	}
}
``` 

The same thing can be achieved by implicitly adding the animation after the scaleEffect modifier

```swift
struct ExplicityAnimationExample2: View {
	@State var scaleSquare = false
	var body: some View {
		Rectangle()
		.fill(Color.red)
		.frame(width: 100, height: 100)
		.scaleEffect(scaleSquare ? 2 : 1)
		.animation(.spring())
		.onAppear {
			scaleSquare.toggle()
		}
	}
}
```

This saves you wrapping the content inside the `withAnimation` block.

The more views you have that require animation the more state changes and view modifiers you will need.

```swift
struct ExplicityAnimationExample3: View {
	@State var scaleSquare = false
	@State var scaleSquare2 = false
	var body: some View {
		VStack(spacing: 150) {
			Rectangle()
			.fill(Color.red)
			.frame(width: 100, height: 100)
			.scaleEffect(scaleSquare ? 2 : 1)
			.animation(.spring())

			Rectangle()
			.fill(Color.blue)
			.frame(width: 100, height: 100)
			.scaleEffect(scaleSquare ? 2 : 1)
			.animation(.spring().speed(0.5))
		}

		.onAppear {
			scaleSquare.toggle()
			scaleSquare2.toggle()
		}
	}
}
```

I find it particular difficult to maintain this is in a nice way, due to the fact that you change state in one place and you have to find the the corresponding animation that matches said change.

So I created a new property wrapper to solve this problem.

I call it AnimatedState.

You can declare the state and animation that you want like so:

```swift
@AnimatedState(
		value: false,
		animation: .spring()
	) var scaleSquare
```

Now if you change that value it will automatically animate with the given animation.

Here is the final version

```swift
struct AnimatedStateExample: View {
	@AnimatedState(
		value: false,
		animation: .spring()
	) var scaleSquare


	@AnimatedState(
		value: false,
		animation: .spring().speed(0.5)
	) var scaleSquare2

	var body: some View {
		VStack(spacing: 150) {
			Rectangle()
			.fill(Color.red)
			.frame(width: 100, height: 100)
			.scaleEffect(scaleSquare ? 2 : 1)

			Rectangle()
			.fill(Color.blue)
			.frame(width: 100, height: 100)
			.scaleEffect(scaleSquare2 ? 2 : 1)
		}

		.onAppear {
			scaleSquare.toggle()
			scaleSquare2.toggle()
		}
	}
}
```

This eliminate the animation modifier for each square or saves you writing the with animation block every time you need to change state.

Hope this is useful for people.

[AnimatedState Gist](https://gist.github.com/vibrazy/3f1b15a38ca74763bd3e411eea8447c4)
[Animating Views and Transitions](https://developer.apple.com/tutorials/swiftui/animating-views-and-transitions)