swiftuiswiftui-animation

How to use frame animation similar to UIKIT in swiftUI


I'm just using swiftUI. I want some one view to have a repeating animation: 1.move up, 2.pause, 3.move up, 4.pause, 5.move down, 6.pause, 7.move down, 8.pause.

Similar to the undulations of pixel wind in Contra.

In UIkit, I can use UIView.animateKeyframes in the block to make the view change.Specify anywhere. In swfitUI I don't know how to do.

can anyone help me?

I have understood that it is not simply moving the y-axis that can achieve the pixel wind effect.

VStack {
                Text("❤️")
                .font(.system(size: 200,weight: .bold))
                .offset(y: offsetY)
                .onAppear{
                    Timer.scheduledTimer(withTimeInterval: 3, repeats: true) { _ in
                        animate()
                    }
                }
}



 func animate() {
        withAnimation(Animation.linear(duration: 0.3)) {
            self.offsetY -= 10
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            withAnimation(Animation.linear(duration: 0.3)) {
                self.offsetY -= 10
            }
        }
        
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.offsetY = 0
        }
    }

Ask about the code obtained after ChatGPT modification,I always feel weird.

  1. I think it should not be done in onAppear block
  2. If I want to specify any view to animate in a method, what should I do? swiftUI cannot
let customView =  Text("❤️")


func somMethod(){
     customView use animate
}

Solution

  • Since iOS 17, keyframeAnimator is available. You can specify the keyframes using that.

    Based on your existing code, you seem to want the heart to move linearly to y offsets -10, -20, -10, and then back to 0. Each move takes 0.3 seconds, and waits for 0.7 seconds between moves. Here is the code with keyframeAnimator.

    struct ContentView: View {
        
        var body: some View {
            Text("❤️")
                .font(.system(size: 200,weight: .bold))
                .keyframeAnimator(initialValue: 0 as CGFloat, repeating: true) { content, value in
                    content.offset(y: value)
                } keyframes: { _ in
                    KeyframeTrack {
                        LinearKeyframe(-10, duration: 0.3)
                        LinearKeyframe(-10, duration: 0.7)
                        LinearKeyframe(-20, duration: 0.3)
                        LinearKeyframe(-20, duration: 0.7)
                        LinearKeyframe(-10, duration: 0.3)
                        LinearKeyframe(-10, duration: 0.7)
                        LinearKeyframe(0, duration: 0.3)
                        LinearKeyframe(0, duration: 0.7)
                    }
                }
        }
    }
    

    If I want to specify any view to animate in a method, what should I do?

    SwiftUI doesn't work imperatively like UIKit. If you want to reuse this code, you can extract it as a view modifier:

    extension View {
        func animateUpAndDown() -> some View {
            self.keyframeAnimator(initialValue: 0 as CGFloat, repeating: true) { content, value in
                content.offset(y: value)
            } keyframes: { _ in
                ...
            }
        }
    }
    

    To use this, just add .animateUpAndDown() like a normal view modifier at the end of the view you want to animate.