Creating a Repeating Animation in SwiftUI
SwiftUI is so amazing because of how much it takes care of for you. When you update the state your view updates automatically. Throw a call to withAnimation
in there and it will even animate the changes! But what if you want an animation that repeats?
Creating the Animation
First thing we need to do is set up our View with something we want to animate. For this example we’ll animate the scale of some text to make it grow and shrink repeatedly.
struct ContentView: View {
@State var isAtMaxScale = false
private let maxScale: CGFloat = 2
var body: some View {
Text("Animations")
.font(.largeTitle)
}
}
The additional properties, isAtMaxScale
and maxScale
, are how the animation is going to be controlled. By checking isAtMaxScale
we can set different values for the scale of the Text, switching it between 1 and maxScale
. You can set the scale of a View with the scaleEffect
modifier:
Text("Animations")
.font(.largeTitle)
.scaleEffect(isAtMaxScale ? 1 : 0)
Now when we toggle isAtMaxScale
the scale of the Text adjusts automatically. But, now we need some way to toggle isAtMaxScale
to kick off the animation. You could use a button to trigger it, but if you want the animation to start right away you can use the onAppear
modifier, and give it an animation with withAnimation
.
Text("Animations")
.font(.largeTitle)
.scaleEffect(isAtMaxScale ? 1 : 0)
.onAppear {
withAnimation(.easeInOut) {
self.isAtMaxScale.toggle()
}
When you call withAnimation
you give it an Animation
to use, then tell it what it is you want to animate. In our case the Animation
curve being used is .easeInOut
, and the state property being animated is isAtMaxScale
.
Making an Animation Repeat
So the code above gives us our animation, but the problem is it still doesn’t repeat. Luckily it’s super easy to create your own animation that repeats!
private let animation = Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)
Here’s an animation that uses the same easeInOut
curve as we were using before, but this time it has a duration of 1 second. It also has a modifier on it to repeatForever
, which is all you need to make a repeating animation! And since we want it to look smooth scaling from small-to-big and back again autoreverses
is true.
Here’s the full code:
struct ContentView: View {
@State var isAtMaxScale = false
private let animation = Animation.easeInOut(duration: 1).repeatForever(autoreverses: true)
private let maxScale: CGFloat = 2
var body: some View {
Text("Animations")
.font(.largeTitle)
.scaleEffect(isAtMaxScale ? maxScale : 1)
.onAppear {
withAnimation(self.animation, {
self.isAtMaxScale.toggle()
})
}
}
}