比例 UIButton 动画-迅捷

我正在尝试为 UIButton做缩放动画当它被点击的时候,但是我正在尝试完成的是当按钮被点击的时候,我需要 UIButton变小到内部,然后它回到它相同的大小(像一个气泡)。

我尝试了以下方法:

button.transform = CGAffineTransformMakeScale(-1, 1)


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


button.transform = CGAffineTransformMakeScale(1,1)


})
109835 次浏览

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)


})

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
}
})

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()  }
)
}

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
}];
}];

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
})
})
}


}

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){}];

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)
})


}

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
})
})

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.
})

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

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")
}
}
}

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
})
})
})
})
})
})

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
}

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
})
}
}

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()
}