I'm building a simple rotating circle loading animation. I've got the circle rotating but the container view is also moving downward for the duration of the animation. I can't figure out what could be causing this strange behavior.
Example:
The White border is the Parent View ZStack
. The Red border is a VStack
that I placed to show this weird animation oddity. The Blue border is a ZStack
that holds the two Circle
s that animate.
Here is the code:
struct CustomLoadingView: View {
let viewWidth: CGFloat = UIScreen.main.bounds.width * 0.5
let backgroundCircleLineWidth: CGFloat = UIScreen.main.bounds.width * 0.025
let foregroundCircleLineWidth: CGFloat = UIScreen.main.bounds.width * 0.02
@State var rotationDegree: Angle = Angle.degrees(0)
var body: some View {
VStack(spacing: 0) {
ZStack {
Circle()
.stroke(style: StrokeStyle(lineWidth: backgroundCircleLineWidth))
.fill(Global.Colors.primary60)
Circle()
.trim(from: 0, to: 0.15)
.stroke(style: StrokeStyle(lineWidth: 7, lineCap: .round))
.fill(Global.Colors.secondary50)
.rotationEffect(self.rotationDegree)
}
.frame(width: viewWidth, height: viewWidth)
.border(Color.blue)
.animation(Animation.linear(duration: 4.5).repeatForever(autoreverses: false), value: rotationDegree)
.onAppear() {
self.animateLoader()
}
}
.border(Color.red)
}
func animateLoader() {
self.rotationDegree = .degrees(720)
}
}
Any idea as to why this is happening and how I can get it to stop? Thanks.
CodePudding user response:
I figured it out with the help of vacawama who linked to a thread in the comments of the question. That thread also had an answer with another helpful link as well. Those were essentially the same problem as I was having here.
Here's the short and sweet:
It boils down to implicit vs explicit animations. In my code, here, I'm using an "explicit" animation. While using an "implicit" animation (withAnimation()
) prevents the problem.
Apparently this may have something to do with how the View
is being animated if the View
is being navigated to. As was my case, I'm showing this View
upon navigation. So the "navigation animation" was getting mixed in with my explicit animation. And, by using an implicit animation, SwiftUI is smart enough to figure out that the navigation animation is not supposed to be part of it.
Here's the code:
var body: some View {
ZStack {
Circle()
.stroke(style: StrokeStyle(lineWidth: backgroundCircleLineWidth))
.fill(Global.Colors.primary60)
Circle()
.trim(from: 0, to: 0.15)
.stroke(style: StrokeStyle(lineWidth: foregroundCircleLineWidth, lineCap: .round))
.fill(Global.Colors.secondary50)
.rotationEffect(self.rotationDegree)
}
.frame(width: viewWidth, height: viewWidth)
.onAppear() {
DispatchQueue.main.async {
withAnimation(Animation.linear(duration: 2.5).repeatForever(autoreverses: false)) {
self.rotationDegree = .degrees(720)
}
}
}
}
I just run the animation inside a withAnimation()
block. And it now works as expected.