Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Repeating animation on SwiftUI Image

Given the following struct:

struct PeopleList : View {
    @State var angle: Double = 0.0
    @State var isAnimating = true

    var foreverAnimation: Animation {
        Animation.linear(duration: 2.0)
            .repeatForever()
    }

    var body: some View {
        Button(action: {}, label: {
            Image(systemName: "arrow.2.circlepath")
                .rotationEffect(Angle(degrees: self.isAnimating ? self.angle : 0.0))
                .onAppear {
                    withAnimation(self.foreverAnimation) {
                        self.angle += 10.0
                    }
                }
        })
    }
}

I was hoping that the Image would rotate clockwise and repeat until self.isAnimating is false although it's only animated once.

like image 807
fulvio Avatar asked Oct 10 '19 04:10

fulvio


People also ask

How do you repeat an animation in Swift?

To make our animation repeat, we use . repeatForever() . The default behavior of repeat forever is autoreverse, that's mean our animation will scale from 1 to 0.5 then 0.5 back to 1, creating a seamless loop of animation.

How do I make an animation in SwiftUI?

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.

Does SwiftUI use Core Animation?

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.


2 Answers

Here is possible solution for continuous progressing on appear & start/stop. Tested with Xcode 11.4 / iOS 13.4.

demo

struct PeopleList : View {
    @State private var isAnimating = false
    @State private var showProgress = false
    var foreverAnimation: Animation {
        Animation.linear(duration: 2.0)
            .repeatForever(autoreverses: false)
    }

    var body: some View {
        Button(action: { self.showProgress.toggle() }, label: {
            if showProgress {
                Image(systemName: "arrow.2.circlepath")
                    .rotationEffect(Angle(degrees: self.isAnimating ? 360 : 0.0))
                    .animation(self.isAnimating ? foreverAnimation : .default)
                    .onAppear { self.isAnimating = true }
                    .onDisappear { self.isAnimating = false }
            } else {
                Image(systemName: "arrow.2.circlepath")
            }
        })
        .onAppear { self.showProgress = true }
    }
}
like image 54
Asperi Avatar answered Sep 27 '22 19:09

Asperi


UPDATE: There is a backspin involved while stopping the animation which is solved with this solution.

I think its this what you are looking for:

struct PeopleList : View {
    @State var angle: Double = 0.0
    @State var isAnimating = false
    
    var foreverAnimation: Animation {
        Animation.linear(duration: 2.0)
            .repeatForever(autoreverses: false)
    }
    
    var body: some View {
        Button(action: {}, label: {
            Image(systemName: "arrow.2.circlepath")
                .rotationEffect(Angle(degrees: self.isAnimating ? 360.0 : 0.0))
                .animation(self.foreverAnimation)
                .onAppear {
                    self.isAnimating = true
            }
        })
    }
}
like image 43
Marc T. Avatar answered Sep 27 '22 20:09

Marc T.