Martin Drlík
Martin Drlík

Reputation: 53

How to create single pulse animation effect in SwiftUI

I would like to scale some view with animation and go back to the original scale. The way I figured out to do it is by using DispatchQueue.main.asyncAfter with deadline matching the end of scale up animation. As shown in following code. My question is if there is better way to do that (more SwiftUI way, or just simpler).

import SwiftUI

struct ExampleView: View {
    @State private var isPulse = false

    var body: some View {
        VStack {
            Text("Hello")
                .scaleEffect(isPulse ? 3 : 1)
            ZStack {
                Capsule()
                    .frame(width: 100, height: 40)
                    .foregroundColor(.pink)
                Text("Press me")
            }
            .onTapGesture {
                let animationDuration = 0.4
                withAnimation(.easeInOut(duration: animationDuration)) {
                    isPulse.toggle()
                }
                DispatchQueue.main.asyncAfter(deadline: .now() + animationDuration) {
                    withAnimation(.easeInOut) {
                        isPulse.toggle()
                    }
                }
            }
        }
    }
}

struct ExampleView_Previews: PreviewProvider {
    static var previews: some View {
        ExampleView()
    }
}

Pulse animation

Upvotes: 3

Views: 709

Answers (1)

vacawama
vacawama

Reputation: 154631

You can use two withAnimation statements with the second one that scales the text down using a .delay(animationDuration):

.onTapGesture {
    let animationDuration = 0.4
    withAnimation(.easeInOut(duration: animationDuration)) {
        isPulse.toggle()
    }
    withAnimation(.easeInOut(duration: animationDuration).delay(animationDuration)) {
        isPulse.toggle()
    }
}

You could also replace the two calls to withAnimation with a for loop:

.onTapGesture {
    let animationDuration = 0.4
    for delay in [0, animationDuration] {
        withAnimation(.easeInOut(duration: animationDuration).delay(delay)) {
            isPulse.toggle()
        }
    }
}

Upvotes: 3

Related Questions