I'm trying to animate a bell icon with the rotation effect but it only animates with the specified angle one way:
struct ContentView: View {
@State var alarmSet = false
var body: some View {
ZStack {
Color.black
VStack {
Image(systemName: "bell.fill")
.font(.system(size: 250))
.foregroundColor(.white)
.rotationEffect(.degrees(reminderSet ? 10 : 0), anchor: .top)
.animation(.interpolatingSpring(mass: 0.5, stiffness: 170, damping: 2.5, initialVelocity: 0), value: alarmSet)
Button(action: {
alarmSet.toggle()
}, label: {
Text(alarmSet ? "Alarm Set" : "Wake Me")
.font(.largeTitle)
.foregroundStyle(.white)
})
.padding(.top, 20)
}
.background(.black)
}
.ignoresSafeArea()
}
}
With the code above, the bell animates between the left side & center, I'd like to get it to
You can use a keyframeAnimator
(iOS 17+)
Image(systemName: "bell.fill")
.font(.system(size: 250))
.foregroundColor(.white)
.keyframeAnimator(initialValue: Angle.zero, trigger: alarmSet) { content, value in
content.rotationEffect(value, anchor: .top)
} keyframes: { _ in
KeyframeTrack {
let spring = Spring(mass: 0.5, stiffness: 170, damping: 2.5)
SpringKeyframe(Angle.degrees(10), duration: 0.05, spring: spring)
// Consider putting this part in a for loop if there are a lot of bounces
SpringKeyframe(Angle.degrees(-10), duration: 0.1, spring: spring)
SpringKeyframe(Angle.degrees(10), duration: 0.1, spring: spring)
SpringKeyframe(Angle.degrees(-10), duration: 0.1, spring: spring)
SpringKeyframe(Angle.degrees(10), duration: 0.1, spring: spring)
// the last frame should have start velocity 0 so that it goes back to the initial position
SpringKeyframe(Angle.zero, duration: 0.05, spring: spring, startVelocity: Angle.zero)
}
}
Also consider using some of the built-in springs.