Reputation: 989
What I expect: That when I press down on the button it shrinks to 75% and stays at its 75% shrunken size until I let go.
What is happening: The buttons shrinks to 75%, but as soon as it finishes the duration of the animation, while my finger is still pressed on the button, it grows back to its original value.
I am called the following when a button is "Touched Down".
import Foundation
import UIKit
extension UIButton {
func shrink() {
let shrink = CABasicAnimation(keyPath: "transform.scale")
shrink.fromValue = 1.0
shrink.toValue = 0.75
shrink.duration = 0.5
shrink.isRemovedOnCompletion = false
layer.add(shrink, forKey: nil)
}
}
Upvotes: 0
Views: 111
Reputation: 110
The size resets because CABasicAnimation doesn't update the layer's underlying value, only the presentation layer. So when the animation ends, it goes back to using the underlying value.
The best way to deal with this is to set the transform scale before the animation starts so that it is the correct value at the end.
func shrink() {
transform = CGAffineTransform(scaleX: 0.75, y: 0.75) // Set final state
let shrink = CABasicAnimation(keyPath: "transform.scale")
shrink.fromValue = 1.0
shrink.toValue = 0.75
shrink.duration = 0.5
layer.add(shrink, forKey: nil)
}
You can also set the fillMode
to .forwards
and isRemovedOnCompletion
to false
, which will keep the presentation layer changes in place, but this doesn't update the layer's actual scale, so the button will keep the original scale for tap detection. (You need to set the transform's scale as above to correct it.)
func shrink() {
let shrink = CABasicAnimation(keyPath: "transform.scale")
shrink.fromValue = 1.0
shrink.toValue = 0.75
shrink.duration = 0.5
shrink.isRemovedOnCompletion = false
shrink.fillMode = .forwards
layer.add(shrink, forKey: nil)
}
You can also use a view animation which will have the same visual effect, but also update the scale:
UIView.animate(withDuration: 0.5) { [weak self] in
self?.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
}
Upvotes: 1