Home > Software engineering >  Mimic spring used in UIKit animation with SwiftUI
Mimic spring used in UIKit animation with SwiftUI

Time:07-12

I'm struggling to figure out how to get SwiftUI's .spring animation to mimic what I'd previously done in UIKit. The UIKit code below animates an ImageView to make it pulse, almost like it's springing when punched, when tapped (.gif below shows this in action, imageView is the name of the imageView being animated). This code immediately shrinks the image by 20 points at each corner (40 pts total), then transitions back to the original size over 0.25 seconds with some spring dampening.

@IBAction func imageTapped(_ sender: UITapGestureRecognizer) {
    let originalImageFrame = imageView.frame
    let imageWidthShrink: CGFloat = 20
    let imageHeightShrink: CGFloat = 20
    let smallerImageFrame = CGRect(
        x: imageView.frame.origin.x   imageWidthShrink,
        y: imageView.frame.origin.y   imageHeightShrink,
        width: imageView.frame.width - (imageWidthShrink * 2),
        height: imageView.frame.height - (imageHeightShrink * 2))
    imageView.frame = smallerImageFrame
    playSound(name: "punchSound")
    UIView.animate(withDuration: 0.25, delay: 0.0, usingSpringWithDamping: 0.2, initialSpringVelocity: 10.0, options: [], animations: {
        self.imageView.frame = originalImageFrame
    })
}

enter image description here

In SwiftUI I can trigger an .animation, putting a .spring inside, triggering this when I tap the image, but it sort of mimics the pulsing but switches between 1.0 and 1.1 scale size. What I want to do is immediately scale to the shorter size, then bounce out to the original size with a spring animation over a time period. Thanks to any sharing insights.

@State private var animateImage = false
...

selectedImage
    .resizable()
    .scaledToFit()
    .scaleEffect(animateImage ? 1.0 : 1.1)
    .animation(.spring(response: 0.3, dampingFraction: 0.3), value: animateImage)
    .onTapGesture {
        print("You tapped me!")
        playSound(name: "punchSound")
        animateImage.toggle()
    }

CodePudding user response:

You can use explicit animation in the tap Gesture to first immediately "shrink" to 0.9 without animation and then expand back WITH animation:

enter image description here

        Image("clown")
            .resizable()
            .scaledToFit()
            .scaleEffect(animateImage ? 0.9 : 1.0)
        
            .onTapGesture {
                animateImage.toggle()
                withAnimation(.spring(response: 0.3, dampingFraction: 0.3)) {
                    animateImage.toggle()
                }
            }
  • Related