Home > database >  SwiftUI Animations: Why is the container view moving? I'm struggling to understand this behavio
SwiftUI Animations: Why is the container view moving? I'm struggling to understand this behavio

Time:11-23

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:

enter image description here

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 Circles 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.

  • Related