I found it tricky to animate a UIImageView
between two states: its original rectangle frame, and a new shape created with a UIBezierPath
. There are man
Another approach is to use a display link. It's like a timer, except it's coordinated with the update of the display. You then have the handler of the display link modify the view according to what it should look like at any particular point of the animation.
For example, if you wanted to animate the rounding of the corners of the mask from 0 to 50 points, you could do something like the following, where percent
is a value between 0.0 and 1.0 indicating what percentage of the animation is done:
let path = UIBezierPath(rect: imageView.bounds)
let mask = CAShapeLayer()
mask.path = path.CGPath
imageView.layer.mask = mask
let animation = AnimationDisplayLink(duration: 0.5) { percent in
let cornerRadius = percent * 50.0
let path = UIBezierPath(roundedRect: self.imageView.bounds, cornerRadius: cornerRadius)
mask.path = path.CGPath
}
Where:
class AnimationDisplayLink : NSObject {
var animationDuration: CGFloat
var animationHandler: (percent: CGFloat) -> ()
var completionHandler: (() -> ())?
private var startTime: CFAbsoluteTime!
private var displayLink: CADisplayLink!
init(duration: CGFloat, animationHandler: (percent: CGFloat)->(), completionHandler: (()->())? = nil) {
animationDuration = duration
self.animationHandler = animationHandler
self.completionHandler = completionHandler
super.init()
startDisplayLink()
}
private func startDisplayLink () {
startTime = CFAbsoluteTimeGetCurrent()
displayLink = CADisplayLink(target: self, selector: "handleDisplayLink:")
displayLink.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSRunLoopCommonModes)
}
private func stopDisplayLink() {
displayLink.invalidate()
displayLink = nil
}
func handleDisplayLink(displayLink: CADisplayLink) {
let elapsed = CFAbsoluteTimeGetCurrent() - startTime
var percent = CGFloat(elapsed) / animationDuration
if percent >= 1.0 {
stopDisplayLink()
animationHandler(percent: 1.0)
completionHandler?()
} else {
animationHandler(percent: percent)
}
}
}
The virtue of the display link approach is that it can be used to animate some property that is otherwise unanimatable. It also lets you to precisely dictate the interim state during the animation.
If you can use CAAnimation
or UIKit
block-based animation, that's probably the way to go. But the display link can sometimes be a good fallback approach.