Internal implementation of UIView's block-based animation methods -
ever since introduction in ios 4, have been wondering internal implementation of uiview
's block-based animation methods. in particular understand mystical features of objective c used there capture relevant layer state changes before , after execution of animation block.
observing black-box implementation, gather needs capture before-state of layer properties modified in animation block, create relevant caanimations
. guess not snapshot of whole view hierarchy, horribly inefficient. animation block opaque code blob during runtime, don't think can analyze directly. replace implementation of property setters on calayer
kind of recoding versions? or support property change recoding baked-in somewhere deep inside calayers
?
to generalize question little bit, possible create similar block-based api recording state changes using objective c dark magic, or rely on knowing , having access internals of objects being changed in block?
it very elegant solution built around fact view layers delegate , stand-alone layers implicitly do animate on property changes.
it happens gave blitz talk @ nsconference couple of days ago , posted my slides on github , tried write down more or less said in presenter notes.
that said: interesting question don't see being asked often. may bit broad i curiosity.
uiview animations existed before ios 4
ever since introduction in ios 4, have been wondering internal implementation of uiview's block-based animation methods.
uiview animations existed before ios 4 in different style (that no longer recommended use because more cumbersome use). example, animating position , color of view delay done this. disclaimer: did not run code may contains bugs.
// setup static void *myanimationcontext = &myanimationcontext; [uiview beginanimations:@"my animation id" context:myanimationcontext]; // configure [uiview setanimationduration:1.0]; [uiview setanimationdelay:0.25]; [uiview setanimationcurve:uiviewanimationcurveeaseinout]; // make changes myview.center = newcenter; myview.backgroundcolor = newcolor; // commit [uiview commitanimations];
the view-layer synergy elegant
in particular understand mystical features of objective c used there capture relevant layer state changes before , after execution of animation block.
it other way around. view built on top of layer , work closely. when set property on view sets corresponding property on layer. can example see the view doesn't have it's own variable frame, bounds or position.
observing black-box implementation, gather needs capture before-state of layer properties modified in animation block, create relevant caanimations.
it not need , this gets elegant. whenever layer property changes, layer looks action (a more general term animation) execute. since setting properties on view sets property on layer, implicitly setting bunch of layer properties.
the first place layer goes looking action asks layer delegate (it documented behaviour view layers delegate). means when layer property changes, layers asks view provide animation object each property change. view doesn't need keep track of state since layer has state , layer asks view provide animation when properties change.
actually, that's not entirely true. view needs keep track of some state such as: if inside of block or not, duration use animation, etc.
you imagine api looks this.
note: don't know actual implementation , obviously huge simplification prove point
// static variables since class method static nstimeinterval _durationtousewhenasked; static bool _isinsideanimationblock; // oversimplified example implementation of how _could_ done + (void)animatewithduration:(nstimeinterval)duration animations:(void (^)(void))animations { _durationtousewhenasked = duration; _isinsideanimationblock = yes; animations(); _isinsideanimationblock = no; } // running animations block going change bunch of properties // result in delegate method being called each property change - (id<caaction>)actionforlayer:(calayer *)layer forkey:(nsstring *)event { // don't animate outside of animation block if (!_isinsideanimationblock) return (id)[nsnull null]; // return nsnull don't animate // animate properties if (![[[self class] arrayofpropertiesthatsupportanimations] containsobject:event]) return (id)[nsnull null]; // return nsnull don't animate cabasicanimation *theanimation = [cabasicanimation animationwithkeypath:event]; theanimation.duration = _durationtousewhenasked; // value seen on screen id oldvalue = [[layer presentationlayer] valueforkeypath:event]; theanimation.fromvalue = oldvalue; // setting value means animating form value model value return theanimation; }
does replace implementation of property setters on calayer kind of recoding versions?
no (see above)
or support property change recoding baked-in somewhere deep inside calayers?
yes, sort of (see above)
creating similar api yourself
to generalize question little bit, possible create similar block-based api recording state changes using objective c dark magic, or rely on knowing , having access internals of objects being changed in block?
you can create similar block based api if want provide own animations based on property changes. if @ techniques showed in talk @ nsconference inspecting uiview animations (directly asking layer actionforlayer:forkey:
, using layerclass
create layer logs addanimation:forkey:
information) should able learn enough how view using layer create abstraction.
i'm not sure if recording state changes end goal or not. if want own animation api shouldn't have to. if want it, could, there wouldn't communication infrastructure (delegate methods , callbacks between view , layer) available there animations.
Comments
Post a Comment