I'm trying to change the colour of my animation based on the state of something. The colour change works but it animates the previous (orange) colour with it. I can't quite work out why both colours are showing. Any ideas?
struct PulsatingView: View {
var state = 1
func colourToShow() -> Color {
switch state {
case 0:
return Color.red
case 1:
return Color.orange
case 2:
return Color.green
default:
return Color.orange
}
}
@State var animate = false
var body: some View {
VStack {
ZStack {
Circle().fill(colourToShow().opacity(0.25)).frame(width: 40, height: 40).scaleEffect(self.animate ? 1 : 0)
Circle().fill(colourToShow().opacity(0.35)).frame(width: 30, height: 30).scaleEffect(self.animate ? 1 : 0)
Circle().fill(colourToShow().opacity(0.45)).frame(width: 15, height: 15).scaleEffect(self.animate ? 1 : 0)
Circle().fill(colourToShow()).frame(width: 6.25, height: 6.25)
}
.onAppear { self.animate.toggle() }
.animation(Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true))
}
}
}
withAnimation() takes a parameter specifying the kind of animation you want, so you could create a three-second linear animation like this: withAnimation(.linear(duration: 3)) Explicit animations are often helpful because they cause every affected view to animate, not just those that have implicit animations attached.
SwiftUI uses Core Animation for rendering by default, and its performance is great for most animations. But if you find yourself creating a very complex animation that seems to suffer from lower framerates, you may want to utilize the power of Metal, which is Apple's framework used for working directly with the GPU.
SwiftUI has built-in support for animations with its animation() modifier. To use this modifier, place it after any other modifiers for your views, tell it what kind of animation you want, and also make sure you attach it to a particular value so the animation triggers only when that specific value changes.
If you want a SwiftUI view to start animating as soon as it appears, you should use the onAppear() modifier to attach an animation.
You change the color, but animating view, which is set up forever is not changed - it remains as set and continues as specified - forever. So it needs to re-set the animation.
Please find below a working full module demo code (tested with Xcode 11.2 / iOS 13.2). The idea is to use ObservableObject
view model as it allows and refresh view and perform some actions on receive. So receiving color changes it is possible to reset and view color and animation.
Updated for Xcode 13.3 / iOS 15.4
Main part is:
}
.onAppear { self.animate = true }
.animation(animate ? Animation.easeInOut(duration: 1.5).repeatForever(autoreverses: true) : .default, value: animate)
.onChange(of: viewModel.colorIndex) { _ in
self.animate = false // << here !!
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.animate = true // << here !!
}
}
Complete findings and code is here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With