Sometimes the built-in animation curves in UIView (or Core Animation for that matter) just don't cut it.
You want to animate a bouncy ball with (somewhat) realistic physics, or just need to use an animation curve that's not ease-in, ease-out, ease-in/out, or linear. But writing a bunch of boilerplate code for setting up your CAKeyframeAnimations can really bog down the flow of your UI code.
Never fear, grab UIView+ExplicitAnimation from the repo on github.
Here's the relevant code for the demo:
CGPoint startCenter = ((CALayer *)[bouncyView.layer presentationLayer]).position;
CGPoint endCenter = bouncyViewCenter;
//Scope for variables in physics simulation
__block double v = -402;
__block double p = startCenter.y;
double elasticity = 0.7;
double g = 1080;
//Add an additional second for each 100 pixel of height we have
double duration = 2.0 + 0.01 * (endCenter.y - startCenter.y);
[UIView animateExplicitlyWithDuration:duration
frameRate:30.0
animations:^(double t, double dt) {
DNUIViewExplicitAnimationProxy *objectProxy = [bouncyView explicitFrameProxy];
DNUIViewExplicitAnimationProxy *shadowProxy = [shadowView explicitFrameProxy];
//Physics simulation here :)
//If we would surpass the target location, bounce instead
if (p + dt * v > endCenter.y) {
v = -elasticity * v;
p = endCenter.y;
} else {
v += g * dt;
p += dt * v;
}
objectProxy.alpha = 1.0 + 0.5 * sin(0.1 * t);
objectProxy.center = (CGPoint) {.x = endCenter.x, .y = p};
double d = endCenter.y - p;
shadowProxy.alpha = 0.8 / (1.0 + 0.01 * d);
shadowProxy.transform = CGAffineTransformMakeScale(1.0 + 0.005 * d,
1.0 + 0.005 * d);
}];
Note how simple it is and there's no boilerplate boxing/unboxing of floats or CGPoints.
I decided on the objectProxy business instead of swizzling -[UIView actionForLayer:forKey:
to get the changes you want in the value of alpha or center or what have you. If you're less timid about swizzling, the proxy business could be eliminated.