SwiftUI is a powerful and expressive framework for creating user interfaces for iOS, macOS, watchOS, and tvOS. One of the features that makes SwiftUI so appealing is its support for animations. With just a few lines of code, you can add stunning effects to your views and make them more engaging and dynamic.
In this article, I will show you how to create a gradient rainbow circle animation using SwiftUI. This animation will display a circle with a gradient fill that changes colors and rotates over time. It will look something like this:
To achieve this effect, we will use the following SwiftUI components:
Circle
: A shape that draws a circle.LinearGradient
: A gradient that applies color transitions along a line.mask
: A modifier that clips a view to the shape of another view.rotationEffect
: A modifier that rotates a view by an angle.animation
: A modifier that applies an animation to a view or a modifier.
Let’s get started!
Creating the gradient
The first step is to create a linear gradient that contains all the colors of the rainbow. We can use the stride
and map
functions to generate an array of colors with different hue values from 0 to 1. Then we can use the LinearGradient
initializer that takes an array of colors and two points that define the start and end of the gradient line.
Here is the code for creating the gradient:
let hueColors = stride(from: 0, to: 1, by: 0.01).map { Color(hue: $0, saturation: 1, brightness: 1) }
let gradient = LinearGradient(gradient: Gradient(colors: hueColors), startPoint: .leading, endPoint: .trailing)
If we preview the gradient, we should see something like this:
Applying the mask
The next step is to apply the gradient as a fill for a circle shape. We can use the fill
modifier to do that. However, if we simply fill the circle with the gradient, we will get a result like this:
This is not what we want. We want the gradient to wrap around the circle, not to stretch across it. To achieve that, we need to use the mask
modifier. This modifier takes another view as an argument and clips the original view to the shape of that view. In our case, we want to mask the gradient with a circle shape.
Here is how we can do that:
gradient.mask(Circle())
Now we should see something like this:
This looks much better. We have successfully created a rainbow circle with a gradient fill.
Adding the animation
The final step is to add some animation to make the circle more lively. We want the circle to rotate and change colors over time. To achieve that, we need to use two modifiers: rotationEffect
and animation
.
The rotationEffect
modifier takes an angle as an argument and rotates the view by that angle. We can use a state variable to store the current angle of rotation and update it periodically using a timer.
The animation
modifier takes an animation as an argument and applies it to the view or a modifier. We can use a linear animation with a duration of 5 seconds and repeat it forever.
Here is how we can add these modifiers:
struct ContentView: View {
@State var angle = Angle(degrees: 0)
let hueColors = stride(from: 0, to: 1, by: 0.01).map { Color(hue: $0, saturation: 1, brightness: 1) }
let gradient = LinearGradient(gradient: Gradient(colors: hueColors), startPoint: .leading, endPoint: .trailing)
var body: some View {
gradient.mask(Circle())
.frame(width: 200, height: 200)
.rotationEffect(angle)
To update the angle of rotation, we need to use a timer. We can use the Timer
class to create a timer that fires every 0.1 seconds and increments the angle by 3 degrees. We can use the onAppear
modifier to start the timer when the view appears.
Here is how we can create and start the timer:
struct ContentView: View {
@State var angle = Angle(degrees: 0)
let hueColors = stride(from: 0, to: 1, by: 0.01).map { Color(hue: $0, saturation: 1, brightness: 1) }
let gradient = LinearGradient(gradient: Gradient(colors: hueColors), startPoint: .leading, endPoint: .trailing)
var body: some View {
gradient.mask(Circle())
.frame(width: 200, height: 200)
.rotationEffect(angle)
.animation(.linear(duration: 5).repeatForever(autoreverses: false))
.onAppear {
let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
self.angle += Angle(degrees: 3)
}
timer.tolerance = 0.01
}
}
}
The tolerance
property of the timer allows us to specify how much the timer can deviate from its scheduled time. This can improve the performance and battery life of the app. We set it to 0.01 seconds, which means the timer can fire up to 0.01 seconds earlier or later than its scheduled time.
Now we have completed the code for creating a gradient rainbow circle animation in SwiftUI. If we run the app, we should see something like this:
Conclusion
In this article, we learned how to create a gradient rainbow circle animation using SwiftUI. We used the following SwiftUI components:
Circle
: A shape that draws a circle.LinearGradient
: A gradient that applies color transitions along a line.mask
: A modifier that clips a view to the shape of another view.rotationEffect
: A modifier that rotates a view by an angle.animation
: A modifier that applies an animation to a view or a modifier.
We also learned how to use a timer to update the angle of rotation and how to use the tolerance
property to improve the performance and battery life of the app.
I hope you enjoyed this article and learned something new. If you have any questions or feedback, please feel free to leave a comment below.
Photo by Alex Jackman on Unsplash
Another Possible Solution
import SwiftUI
struct GradientCircle: View {
@State private var rotation = 0.0
let colors = [Color.red, Color.red, Color.orange, Color.yellow, Color.green, Color.blue, Color.purple]
var body: some View {
Circle()
.strokeBorder(LinearGradient(gradient: Gradient(colors: colors), startPoint: .topLeading, endPoint: .bottomTrailing), lineWidth: 20)
.frame(width: 100, height: 100)
.rotationEffect(.degrees(rotation))
.animation(Animation.linear(duration: 2).repeatForever(autoreverses: false))
.onAppear {
rotation = 360
}
}
}
struct ContentView: View {
var body: some View {
GradientCircle()
}
}