I'm trying to recreate the sparkle effect from Apple's activity ring animation using SwiftUI. I've found Paul Hudson's Vortex library, which includes a sparkle effect, but as a beginner in SwiftUI animations, I'm struggling to modify it to match my vision. Can anyone offer guidance on how to achieve this effect?
Here's the Vortex project I'm referring to: Vortex project
This is what I envision it should look like: YouTube Link
This YouTube video shows the effect I'm aiming for: YouTube Link
I have attempted to implement it, but the result isn't what I expected. Here's my current code:
import SwiftUI
import Foundation
import Vortex
struct ContentView: View {
@State private var isAnimatingFast = false
var foreverAnimationFast: Animation {
Animation.linear(duration: 1.0)
.repeatForever(autoreverses: false)
}
@State private var isAnimatingSlow = false
var foreverAnimationSlow: Animation {
Animation.linear(duration: 1.5)
.repeatForever(autoreverses: false)
}
var body: some View {
ZStack {
VortexView(customMagic) {
Circle()
.fill(.blue)
.frame(width: 10, height: 10)
.tag("sparkle")
}
.frame(width: 250, height: 250)
.rotationEffect(Angle(degrees: isAnimatingFast ? 360 : 0.0))
.onAppear {
withAnimation(foreverAnimationFast) {
isAnimatingFast = true
}
}
.onDisappear { isAnimatingFast = false }
VortexView(customSpark) {
Circle()
.fill(.white)
.frame(width: 20, height: 20)
.tag("circle")
}
.rotationEffect(Angle(degrees: isAnimatingSlow ? 360 : 0.0))
.onAppear {
withAnimation(foreverAnimationSlow) {
isAnimatingSlow = true
}
}
.onDisappear { isAnimatingSlow = false }
VortexView(customSpark) {
Circle()
.fill(.white)
.frame(width: 20, height: 20)
.tag("circle")
}
.rotationEffect(Angle(degrees: isAnimatingSlow ? 180 : -180))
VortexView(customSpark) {
Circle()
.fill(.white)
.frame(width: 20, height: 20)
.tag("circle")
}
.rotationEffect(Angle(degrees: isAnimatingSlow ? 90 : -370))
VortexView(customSpark) {
Circle()
.fill(.white)
.frame(width: 20, height: 20)
.tag("circle")
}
.rotationEffect(Angle(degrees: isAnimatingSlow ? 370 : -90))
}
}
}
let customMagic =
VortexSystem(
tags: ["sparkle"],
shape: .ring(radius: 0.5),
lifespan: 1.5,
speed: 0,
angleRange: .degrees(360),
colors: .random(.red, .pink, .orange, .blue, .green, .white),
size: 0.5
)
let customSpark = VortexSystem(
tags: ["circle"],
birthRate: 150,
emissionDuration: 0.2,
idleDuration: 0,
lifespan: 0.75,
speed: 1,
speedVariation: 0.2,
angle: .degrees(330),
angleRange: .degrees(20),
acceleration: [0, 3],
dampingFactor: 4,
colors: .ramp(.white, .yellow, .yellow.opacity(0)),
size: 0.1,
sizeVariation: 0.1,
stretchFactor: 8
)
#Preview {
ContentView()
}
Any insights or suggestions on how to better match the desired animation effect would be greatly appreciated!
i'm guessing you will have a hard time reproducing that video using Vortex inside SwiftUI (as opposed to doing the whole thing using particles in spritekit). but here's a rough approximation
import SwiftUI
import Foundation
import Vortex
struct ContentView: View {
@State private var isAnimating = false
var body: some View {
ZStack {
Color.black
Group {
ForEach(0..<18) { index in
//a single pinwheel sparkler
VortexView(customSpark) {
Circle()
.fill(.white)
.blendMode(.plusLighter)
.frame(width: 32)
.tag("circle")
}
.frame(width:200, height:200)
.offset(y:-100)
.rotationEffect(Angle(degrees: Double(index) * 20))
.opacity(isAnimating ? 1 : 0)
.animation(
Animation.easeInOut(duration: 0.2)
.delay(Double(index) * 0.075),
value: isAnimating
)
}
.onAppear {
withAnimation {
isAnimating = true
}
//disappear in a ring
Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { _ in
withAnimation {
isAnimating = false
}
}
}
}
.onAppear {
withAnimation {
isAnimating = true
}
}
}
}
}
//pinwheel sparkler
let customSpark = VortexSystem(
tags: ["circle"],
birthRate: 20,
emissionDuration: 5,
lifespan: 2,
speed: 0.75,
speedVariation: 0.5,
angle: .degrees(90),
angleRange: .degrees(8),
colors: .ramp(.white, .red, .red.opacity(0)),
size: 0.06
)
#Preview {
ContentView()
}