Exploring SwiftUI: Animating Mesh Gradient with Colors in iOS 18
44% OFF - Black Friday Sale
Use the coupon "BLACKFRIDAY" at checkout page for AI Driven Coding, Foundation Models MLX, MusicKit, freelancing or technical writing.
I have been working with the new MeshGradient structure in SwiftUI for a month now, and feels like I barely scratched the surface. I am exploring animating the gradients, and we are going to create an animated mesh gradient using only colors. It is easier than you might think, and the results are gorgeous, as it should be. Let us dive in!
What is a Mesh Gradient?
What exactly is a mesh gradient? It is a type of gradient that uses multiple colors arranged in a grid. They are more complex and flexible version of a regular linear gradient.
- In a 2x2 grid, you are somewhat limited. The color points are stuck at the edges of the shape.
- With a 3x3 grid (like we are using in this example), you have a point in the center that you can move around, giving you more control over how colors blend.
- In a 4x4 grid, you have even more flexibility. There are 4 points in the middle that you can adjust, letting you create more complex color transitions and even tangent-like effects like in the gradient below!
The more points you have, the more organic the gradient can become. For a simple example, I am using a 3x3 grid.
Setting Up Our Colors and Points
We start by defining the colors and points. Here is what that looks like:
private let colors: [Color] = **[Color(red: 1.00, green: 0.42, blue: 0.42),](/posts/colorred-100-green-042-blue-042)**
Here is the full code to copy and explore in your project:
```swift
struct AnimatedColorsMeshGradientView: View {
private let colors: [Color] = [
Color(red: 1.00, green: 0.42, blue: 0.42),
Color(red: 1.00, green: 0.55, blue: 0.00),
Color(red: 1.00, green: 0.27, blue: 0.00),
Color(red: 1.00, green: 0.41, blue: 0.71),
Color(red: 0.85, green: 0.44, blue: 0.84),
Color(red: 0.54, green: 0.17, blue: 0.89),
Color(red: 0.29, green: 0.00, blue: 0.51),
Color(red: 0.00, green: 0.00, blue: 0.55),
Color(red: 0.10, green: 0.10, blue: 0.44)
]
private let points: [SIMD2<Float>] = [
SIMD2<Float>(0.0, 0.0), SIMD2<Float>(0.5, 0.0), SIMD2<Float>(1.0, 0.0),
SIMD2<Float>(0.0, 0.5), SIMD2<Float>(0.5, 0.5), SIMD2<Float>(1.0, 0.5),
SIMD2<Float>(0.0, 1.0), SIMD2<Float>(0.5, 1.0), SIMD2<Float>(1.0, 1.0)
]
}
extension AnimatedColorsMeshGradientView {
var body: some View {
TimelineView(.animation) { timeline in
MeshGradient(
width: 3,
height: 3,
locations: .points(points),
colors: .colors(animatedColors(for: timeline.date)),
background: .black,
smoothsColors: true
)
}
.ignoresSafeArea()
}
}
extension AnimatedColorsMeshGradientView {
private func animatedColors(for date: Date) -> [Color] {
let phase = CGFloat(date.timeIntervalSince1970)
return colors.enumerated().map { index, color in
let hueShift = cos(phase + Double(index) * 0.3) * 0.1
return shiftHue(of: color, by: hueShift)
}
}
private func shiftHue(of color: Color, by amount: Double) -> Color {
var hue: CGFloat = 0
var saturation: CGFloat = 0
var brightness: CGFloat = 0
var alpha: CGFloat = 0
UIColor(color).getHue(&hue, saturation: &saturation, brightness: &brightness, alpha: &alpha)
hue += CGFloat(amount)
hue = hue.truncatingRemainder(dividingBy: 1.0)
if hue < 0 {
hue += 1
}
return Color(hue: Double(hue), saturation: Double(saturation), brightness: Double(brightness), opacity: Double(alpha))
}
}
# Preview {
AnimatedColorsMeshGradientView()
}Happy meshing!
44% OFF - Black Friday Sale
Use the coupon "BLACKFRIDAY" at checkout page for AI Driven Coding, Foundation Models MLX, MusicKit, freelancing or technical writing.