Scale UIButton Animation- Swift [closed]
Asked Answered
T

15

90

I'm trying to do scale animation for UIButton when its clicked but what I'm trying to accomplish is when the button clicked I need the UIButton to be smaller to the inside then it comes back to its same size (like a bubble).

I tried the following:

button.transform = CGAffineTransformMakeScale(-1, 1)

UIView.animateWithDuration(0.5, animations: { () -> Void in

    button.transform = CGAffineTransformMakeScale(1,1)

})
Traitorous answered 9/7, 2015 at 14:42 Comment(1)
What happened when you tried the code you have included?Creed
W
193

Try this

UIView.animate(withDuration: 0.6,
    animations: {
        self.button.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)
    },
    completion: { _ in
        UIView.animate(withDuration: 0.6) {
            self.button.transform = CGAffineTransform.identity
        }
    })
Washrag answered 9/7, 2015 at 15:28 Comment(2)
Swift 3.0: UIView.animate(withDuration: 0.6, animations: { self.button.transform = CGAffineTransform(scaleX: 0.6, y: 0.6) }, completion: { (finish: Bool) in UIView.animate(withDuration: 0.6, animations: { self.button.transform = CGAffineTransform.identity }) })Harmony
Another way to create pop up gesture on UIButton let scaleValue : CGFloat = btn.isSelected ? 1.2 : 1.1 UIView.animate(withDuration: 0.3, animations: { btn.transform = CGAffineTransform(scaleX: scaleValue, y: scaleValue) }, completion: { _ in UIView.animate(withDuration: 0.3) { btn.transform = CGAffineTransform.identity } })Flytrap
S
78

SWIFT 5 Code Update :I have animated button with a nice bouncing effect , with spring animation.

@IBOutlet weak var button: UIButton!

@IBAction func animateButton(sender: UIButton) {

    sender.transform = CGAffineTransform(scaleX: 0.6, y: 0.6)

    UIView.animate(withDuration: 2.0,
                               delay: 0,
                               usingSpringWithDamping: CGFloat(0.20),
                               initialSpringVelocity: CGFloat(6.0),
                               options: UIView.AnimationOptions.allowUserInteraction,
                               animations: {
                                sender.transform = CGAffineTransform.identity
        },
                               completion: { Void in()  }
    )
}
Smithy answered 9/11, 2015 at 10:46 Comment(0)
I
34

All of the answers above are valid.
As a plus, with Swift I suggest to create an extension of UIView in order to "scale" any view you want.
You can take inspiration from this piece of code:

SWIFT 5.0

extension UIView {

/**
 Simply zooming in of a view: set view scale to 0 and zoom to Identity on 'duration' time interval.

 - parameter duration: animation duration
 */
func zoomIn(duration: TimeInterval = 0.2) {
    self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
    UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear], animations: { () -> Void in
        self.transform = .identity
        }) { (animationCompleted: Bool) -> Void in
    }
}

/**
 Simply zooming out of a view: set view scale to Identity and zoom out to 0 on 'duration' time interval.

 - parameter duration: animation duration
 */
func zoomOut(duration : TimeInterval = 0.2) {
    self.transform = .identity
    UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear], animations: { () -> Void in
        self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
        }) { (animationCompleted: Bool) -> Void in
    }
}

/**
 Zoom in any view with specified offset magnification.

 - parameter duration:     animation duration.
 - parameter easingOffset: easing offset.
 */
func zoomInWithEasing(duration: TimeInterval = 0.2, easingOffset: CGFloat = 0.2) {
    let easeScale = 1.0 + easingOffset
    let easingDuration = TimeInterval(easingOffset) * duration / TimeInterval(easeScale)
    let scalingDuration = duration - easingDuration
    UIView.animate(withDuration: scalingDuration, delay: 0.0, options: .curveEaseIn, animations: { () -> Void in
        self.transform = CGAffineTransform(scaleX: easeScale, y: easeScale)
        }, completion: { (completed: Bool) -> Void in
            UIView.animate(withDuration: easingDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
                self.transform = .identity
                }, completion: { (completed: Bool) -> Void in
            })
    })
}

/**
 Zoom out any view with specified offset magnification.

 - parameter duration:     animation duration.
 - parameter easingOffset: easing offset.
 */
func zoomOutWithEasing(duration: TimeInterval = 0.2, easingOffset: CGFloat = 0.2) {
    let easeScale = 1.0 + easingOffset
    let easingDuration = TimeInterval(easingOffset) * duration / TimeInterval(easeScale)
    let scalingDuration = duration - easingDuration
    UIView.animate(withDuration: easingDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
        self.transform = CGAffineTransform(scaleX: easeScale, y: easeScale)
        }, completion: { (completed: Bool) -> Void in
            UIView.animate(withDuration: scalingDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
                self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
                }, completion: { (completed: Bool) -> Void in
            })
    })
}

}

Usage is very simply:

let button = UIButton(frame: frame)
button.zoomIn() // here the magic

Swift 3 Version

extension UIView {

/**
 Simply zooming in of a view: set view scale to 0 and zoom to Identity on 'duration' time interval.

 - parameter duration: animation duration
 */
func zoomIn(duration: TimeInterval = 0.2) {
    self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
    UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear], animations: { () -> Void in
        self.transform = CGAffineTransform.identity
    }) { (animationCompleted: Bool) -> Void in
    }
}

/**
 Simply zooming out of a view: set view scale to Identity and zoom out to 0 on 'duration' time interval.

 - parameter duration: animation duration
 */
func zoomOut(duration: TimeInterval = 0.2) {
    self.transform = CGAffineTransform.identity
    UIView.animate(withDuration: duration, delay: 0.0, options: [.curveLinear], animations: { () -> Void in
        self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
    }) { (animationCompleted: Bool) -> Void in
    }
}

/**
 Zoom in any view with specified offset magnification.

 - parameter duration:     animation duration.
 - parameter easingOffset: easing offset.
 */
func zoomInWithEasing(duration: TimeInterval = 0.2, easingOffset: CGFloat = 0.2) {
    let easeScale = 1.0 + easingOffset
    let easingDuration = TimeInterval(easingOffset) * duration / TimeInterval(easeScale)
    let scalingDuration = duration - easingDuration
    UIView.animate(withDuration: scalingDuration, delay: 0.0, options: .curveEaseIn, animations: { () -> Void in
        self.transform = CGAffineTransform(scaleX: easeScale, y: easeScale)
    }, completion: { (completed: Bool) -> Void in
        UIView.animate(withDuration: easingDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
            self.transform = CGAffineTransform.identity
        }, completion: { (completed: Bool) -> Void in
        })
    })
}

/**
 Zoom out any view with specified offset magnification.

 - parameter duration:     animation duration.
 - parameter easingOffset: easing offset.
 */
func zoomOutWithEasing(duration: TimeInterval = 0.2, easingOffset: CGFloat = 0.2) {
    let easeScale = 1.0 + easingOffset
    let easingDuration = TimeInterval(easingOffset) * duration / TimeInterval(easeScale)
    let scalingDuration = duration - easingDuration
    UIView.animate(withDuration: easingDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
        self.transform = CGAffineTransform(scaleX: easeScale, y: easeScale)
    }, completion: { (completed: Bool) -> Void in
        UIView.animate(withDuration: scalingDuration, delay: 0.0, options: .curveEaseOut, animations: { () -> Void in
            self.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)
        }, completion: { (completed: Bool) -> Void in
        })
    })
}

}
Immensurable answered 17/2, 2016 at 11:6 Comment(0)
M
22

Swift 3.x+

extension UIButton {

        func pulsate() {

            let pulse = CASpringAnimation(keyPath: "transform.scale")
            pulse.duration = 0.2
            pulse.fromValue = 0.95
            pulse.toValue = 1.0
            pulse.autoreverses = true
            pulse.repeatCount = 2
            pulse.initialVelocity = 0.5
            pulse.damping = 1.0

            layer.add(pulse, forKey: "pulse")
        }

        func flash() {

            let flash = CABasicAnimation(keyPath: "opacity")
            flash.duration = 0.2
            flash.fromValue = 1
            flash.toValue = 0.1
            flash.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
            flash.autoreverses = true
            flash.repeatCount = 3

            layer.add(flash, forKey: nil)
        }


        func shake() {

            let shake = CABasicAnimation(keyPath: "position")
            shake.duration = 0.05
            shake.repeatCount = 2
            shake.autoreverses = true

            let fromPoint = CGPoint(x: center.x - 5, y: center.y)
            let fromValue = NSValue(cgPoint: fromPoint)

            let toPoint = CGPoint(x: center.x + 5, y: center.y)
            let toValue = NSValue(cgPoint: toPoint)

            shake.fromValue = fromValue
            shake.toValue = toValue

            layer.add(shake, forKey: "position")
        }
    }

Usage:

myButton.flash()
// myButton.pulsate()
// myButton.shake()

Credits: Sean Allen

Markswoman answered 15/6, 2017 at 10:24 Comment(0)
G
16

Swift 3 Version:

    UIView.animate(withDuration: 0.6, animations: {
        button.transform = CGAffineTransform.identity.scaledBy(x: 0.6, y: 0.6)
        }, completion: { (finish) in
            UIView.animate(withDuration: 0.6, animations: {
                button.transform = CGAffineTransform.identity
            })
    })
Gatehouse answered 21/9, 2016 at 7:30 Comment(0)
T
10

It works with me as following, the animation is set to be small then when it start animation it get back to its original size:

Swift 2

button.transform = CGAffineTransformMakeScale(0.6, 0.6)

UIView.animateWithDuration(0.3, animations: { () -> Void in

    button.transform = CGAffineTransformMakeScale(1,1)

})

Swift 3, 4, 5

button.transform = CGAffineTransform.init(scaleX: 0.6, y: 0.6)

UIView.animate(withDuration: 0.3, animations: { () -> Void in

    button.transform = CGAffineTransform.init(scaleX: 1, y: 1)

})
Traitorous answered 9/7, 2015 at 14:57 Comment(1)
Your code immediately set the size of button to be 0.6, and then animate it back to the original size. However, if you want to animate to 0.6 and then animate back to original size. Check out my answer.Washrag
B
10

Using Swift 4 Xcode 9, This will animate the button down when initially pressed and then back up when released.

extension UIView {

func animateButtonDown() {

    UIView.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseIn], animations: {
        self.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
    }, completion: nil)
}

func animateButtonUp() {

    UIView.animate(withDuration: 0.1, delay: 0.0, options: [.allowUserInteraction, .curveEaseOut], animations: {
        self.transform = CGAffineTransform.identity
    }, completion: nil)
}

Implementation:

@IBAction func buttonTouchDown(_ sender: UIButton) {
    //Connected with Touch Down Action
    sender.animateButtonDown()
}

@IBAction func buttonTouchUpOutside(_ sender: UIButton) {
    //Connected with Touch Up Outside Action
    //if touch moved away from button
    sender.animateButtonUp()
}

@IBAction func buttonTouchUpInside(_ sender: UIButton) {
    //Connected with Touch Up Inside Action
    sender.animateButtonUp()
    //code to execute when button pressed
}
Bertiebertila answered 28/4, 2018 at 10:49 Comment(0)
U
5

I prefer to have the press animation and set it more fast than the other examples, with the completion control for waiting until the animation is ended:

Swift 3:

extension UIButton {
   func press(completion:@escaping ((Bool) -> Void)) {
            UIView.animate(withDuration: 0.05, animations: {
                self.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) }, completion: { (finish: Bool) in
                    UIView.animate(withDuration: 0.1, animations: {
                        self.transform = CGAffineTransform.identity
                        completion(finish)
                    })
            })
    }
}

Usage:

@IBAction func playPauseBtnTap(_ sender: Any) {
     let playPauseBtn = sender as! UIButton
     playPauseBtn.press(completion:{ finish in
         if finish {
             print("animation ended")
         }
     }
}
Ulent answered 16/7, 2017 at 6:52 Comment(1)
good use of the completion to launch stuff on a thread without have that ridiculous spinning circle crapIrradiance
P
3

Using the following animation the button will start from its full size, decrease to 0.6 with a spring animation to bounce back to it's full size.

[UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.4 initialSpringVelocity:0.3 options:0 animations:^{
                //Animations
                button.transform = CGAffineTransformIdentity;
                CGAffineTransformMakeScale(0.6, 0.6)
            } completion:^(BOOL finished) {
                //Completion Block
            [UIView.animateWithDuration(0.5){
            button.transform = CGAffineTransformIdentity
             }];
            }];
Priesthood answered 18/11, 2015 at 12:2 Comment(0)
I
3

You can try this if you want a Autoreverse effect with a completion handler.

viewToAnimate.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        UIView.animate(withDuration: 0.7, // your duration
                       delay: 0,
                       usingSpringWithDamping: 0.2,
                       initialSpringVelocity: 6.0,
                       animations: { _ in
                       viewToAnimate.transform = .identity
            },
                       completion: { _ in
                        // Implement your awesome logic here.
        })
Ingle answered 28/11, 2016 at 8:29 Comment(0)
L
2

iOS 9 and xCode 7

//for zoom in
    [UIView animateWithDuration:0.5f animations:^{

        self.sendButton.transform = CGAffineTransformMakeScale(1.5, 1.5);
    } completion:^(BOOL finished){}];
// for zoom out
        [UIView animateWithDuration:0.5f animations:^{

            self.sendButton.transform = CGAffineTransformMakeScale(1, 1);
        }completion:^(BOOL finished){}];
Likker answered 16/8, 2016 at 10:3 Comment(0)
P
2

This will give a wonderful bouncing effect:

@IBAction func TouchUpInsideEvent(sender: UIButton) {
    UIView.animateWithDuration(2.0,
                               delay: 0,
                               usingSpringWithDamping: CGFloat(0.20),
                               initialSpringVelocity: CGFloat(6.0),
                               options: UIViewAnimationOptions.AllowUserInteraction,
                               animations: {
                                sender.transform = CGAffineTransformIdentity
        },
                               completion: { Void in()  }
    )
}


@IBAction func touchDownEvent(sender: UIButton) {
    UIView.animateWithDuration(0.15, animations: {
        sender.transform = CGAffineTransformMakeScale(0.6, 0.6)
    })

}
Pericycle answered 20/8, 2016 at 13:20 Comment(0)
S
2

Scaling Button or any view about three times or more use following code. swift 3 or swift 4 with xcode 9.

 UIView.animate(withDuration: 0.2, animations: {
        self.cartShowHideBtnView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)

    }, completion: { (finish: Bool) in
            UIView.animate(withDuration: 0.2, animations: {
                self.cartShowHideBtnView.transform = CGAffineTransform.identity

            }, completion:{(finish: Bool) in
                UIView.animate(withDuration: 0.2, animations: {
                    self.cartShowHideBtnView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)

                }, completion: { (finish: Bool) in
                    UIView.animate(withDuration: 0.2, animations: {
                        self.cartShowHideBtnView.transform = CGAffineTransform.identity

                    }, completion:{(finish: Bool) in
                        UIView.animate(withDuration: 0.2, animations: {
                            self.cartShowHideBtnView.transform = CGAffineTransform(scaleX: 1.3, y: 1.3)

                        }, completion: { (finish: Bool) in
                            UIView.animate(withDuration: 0.2, animations: {
                                self.cartShowHideBtnView.transform = CGAffineTransform.identity
                        })
                    })
                })
            })
        })
    })
Sententious answered 13/11, 2017 at 12:0 Comment(0)
I
1

I did a protocol using Swift 4, that you can use at some specifics UIViews that you want to animate... You can try some animations over here or change time and delay.

This way is recommended because you can use this protocol and others at one view and this view can use this functions, doing a lot os extensions from UIView create code smell.

import Foundation
import UIKit

protocol Showable where Self: UIView {}

extension Showable {

    func show(_ view: UIView? = nil) {

        if let view = view {
            self.animate(view)
        } else {
            self.animate(self)
        }
    }

    private func animate(_ view: UIView) {
        view.transform = CGAffineTransform(scaleX: 0.0, y: 0.0)

        UIView.animate(withDuration: 2.0,
                       delay: 0,
                       usingSpringWithDamping: CGFloat(0.20),
                       initialSpringVelocity: CGFloat(6.0),
                       options: [.allowUserInteraction],
                       animations: {
                        view.transform = CGAffineTransform.identity
        })
    }
}
Infernal answered 19/8, 2018 at 6:1 Comment(1)
Please also add an example of using this extension.Markswoman
B
1

Here is a working example :

extension  UIButton{
  func flash() {
    let flash = CABasicAnimation(keyPath: "opacity")
    flash.duration = 0.5
    flash.fromValue = 1
    flash.toValue = 0.1
    flash.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
    flash.autoreverses = true
    flash.repeatCount = 3
    layer.add(flash, forKey: nil)
  }
}

@IBAction func taptosave(_ sender: UIButton) {
  sender.flash()
}
Billingsley answered 3/1, 2019 at 12:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.