Seeing that this is the only mention of this issue (feature?) that I've found anywhere over the past year and a half, let me first thank you for being my only source of sanity. With that, I've finally been able to circle back and demystify this...sort of. I've yet to file a radar, only because it is unclear whether this behavior is intended. Whatever the correct behavior, the animation has some odd side-effects, and led me to report a separate issue.
The Problem
To boil it down, the image
field is not an animatable field, but updating it outside of a user-defined transaction triggers a system-performed path animation from the previous image to the new image. Since the animations are performed at the layer-level, UIKit
will not be able to stop them. Instead, we have to halt the current thread transaction's animation actions entirely so that the nested layer animations are never allowed to perform:
CATransaction.begin()
CATransaction.setDisableActions(true)
annotationView.image = newImage
CATransaction.commit()
Modifying Existing Animation
Rather than cutting off the animation completely, you can also de-jank the path animation by injecting your own properties to the current thread transaction. The catch here, though, is that in order to correctly animate the path & make the appearance that the image isn't moving (ex. animating from a small pin to a large pin), we have to synchronize an additional animation of the centerOffset
. This field does not
directly modify the layer, but it does appear to be a UIKit-animatable field. This means that you need to combine a UIKit animation with a CoreAnimation transaction:
CATransaction.begin()
CATransaction.setAnimationDuration(animationDuration)
CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: .easeIn))
UIView.animate(withDuration: animationDuration, delay: 0, options: .curveEaseIn, animations: {
self.image = newImage
self.centerOffset = newCenterOffset
}, completion: nil)
CATransaction.commit()
The duration & timing function must be the same for both the UIKit animation & the CoreAnimation transaction.
[UIView performWithoutAnimation:^{}]
but not works. This weird animation is really annoying. – Montana