-
Notifications
You must be signed in to change notification settings - Fork 0
Animation
I've tried to get basic animation working for years, and always failed. Apple's examples are never quite the same as mine, or it works in a trivial test app but not reliably in my actual app, or I find mountains of documentation for UIKit (which is very different, as usual, for no apparent reason) and it uses features which don't exist in AppKit.
This weekend, I think I got it figured out. The key was in WWDC 2012 #228.
The two key points that I got from this:
- Don't trust CoreAnimation, or
allowsImplicitAnimation
. Just animate it yourself. - Don't trust that the animation and layout engines will play nice with temporarily invalid constraints. (In other places, Apple engineers seem to imply that this can work, but in my testing it's not at all reliable.) Come up with a way to animate your system using only always-valid constraints.
In pseudocode, this amounts to:
// 1. to force all pending layout to complete
layoutSubtreeIfNeeded()
// 2. compute positions
compute starting (current) position of view (relative to superview, for example)
compute ending position of view
subtract these to get dx/dy/dw/dh between the two frames
// 3. constraints changeover
deactivate existing constraints on your view
create new constraints to position your new view at the ending position, with extra constants +dx/dy/dw/dh to move it back to the starting (current) position
activate these new constraints
// 4. run animation to final position
NSAnimationContext.runAnimationGroup {
for each constraint, call constraint.animator().constant = finalConstant
}
Don't be afraid of assigning constraint.constant
in a loop. Apple says they specifically optimized that case and intend it to be used during drags/swipes, so it's good enough for your animation.
Note: in the function for the user action that triggered the animation, make the animation the final step. If you go and say needsUpdateConstraints = true
on the same view after starting the animation, weird things will happen. You wouldn't do this intentionally (it'd be pointless), but it's easy to do accidentally from a big "fix all the things" method that wasn't aware animation might be starting.