Re: Controlling some of CoreAnimation's more confusing automation
Re: Controlling some of CoreAnimation's more confusing automation
- Subject: Re: Controlling some of CoreAnimation's more confusing automation
- From: Andreas Grosam <email@hidden>
- Date: Thu, 21 May 2009 11:34:04 +0200
On May 21, 2009, at 4:04 AM, Gwynne Raskind wrote:
I have a UIView that contains a number of CALayers. Nothing unusual
here. The CALayers are subclassed to do their drawing, because that
was easier than separating the delegate logic from my UIView
subclass (since the view can't be the delegate of a sublayer - it
causes an infinite recursion to do so, why isn't there a check for
this somewhere in CA's or Cocoa Touch's code?).
Each time I call [anInstanceOfCALayer setNeedsDisplay], to update
changes I've made to the layer's custom properties, Core Animation
performs an implicit animation from the old cached data to the new
draw state. For example, if I change a property so that my drawing
code fills a path that was previously empty, the UI shows the filled
space fading into existence.
I've figured out that I can explicitly disable this using the
CATransaction calls wrapped around my call to -setNeedsDisplay. But
I'd like to either:
1) animate the custom properties more directly with a
CABasicAnimation. I tried this, but it did nothing at all.
2) get some control over the implicit animation CA is setting up for
the contents transition. CATransaction only lets me set duration and
the "is enabled" flag, whereas CAMediaTiming has a whole pile of
useful parameters.
Any help would be appreciated.
Form your description, I can't see where the specific issue is. So I
just post an example which will work (a modified working code, but
changed for this example and not tested). Hope this helps:
I'm assuming you have a somewhat more complex layer hierarchy. Instead
of subclassing a layer, I would define a "model" that has a visual
representation in a UI. Say, this model is composed of a set of
"shapes". But this design is up to you.
Instances of Shape are associated to a layer. It is assumed that a
layer is only used by one shape. A Shape instance also has parameters
which define a certain animation that will be triggered when a certain
state change occurs on the instance:
Shape:
- (void) changeStateTo:(int)aState
{
// Calculate the effect of a state change:
// In this example it is a rotation of the shape, which will be
visualized by a single animation
// that causes the layer to rotate:
// (get the current rotation of this shape in radians)
// (perform state change on the model)
CGFloat fromRotation = self.currentRotation;
[self private_changeStateTo:aState];
CGFloat toRotation = self.currentRotation;
// Create a rotation animation around z axis by using animation
parameters hold by the Shape instance:
CABasicAnimation* animation = [CABasicAnimation animation];
animation.keyPath = @"transform.rotation.z";
animation.fromValue = [NSNumber numberWithFloat:fromRotation];
animation.toValue = [NSNumber numberWithFloat:toRotation];
animation.duration = (self.animationDuration);
animation.repeatCount = 0;
// Leave the presentation layer in its final state (preventing
snap-back to original state),
// or in other words, match the state of the shape with its
visual representation:
// (note: there are alternatives to accomplish this)
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeBoth;
// Set a timing function (you may get required animation
parameters from the Shape instance);
animation.timingFunction = [CAMediaTimingFunction
functionWithName:kCAMediaTimingFunctionLinear];
// The delegate may handle CAAnimation delegate methods. The
shape instance itself would be a
// good candidate to become the delegate:
animation.delegate = self;
// Add the animation to the shapes's layer. Note that this
immediately causes the animation to
// start (asynchronously). setNeedsDisplay is not required!
// This will also stop a possibly running anmimation with the
same key.
[self.layer addAnimation:animation forKey:self.name];
}
Of course, you can setup any animation type, or an animation group.
The layer associated to a shape may be part of a layer hierarchy.
Setting up the layer hierarchy that models the visual representation
of your set of (possibly hierarchically layered) shapes is a different
thing though, and not shown.
The delegate methods can be used to determine when the animation
starts and when it has been finished, and whether it has been
interrupted by another animation.
This method can be called from any thread.
This design moves completely the "how to animate a certain model
state change" from the view controller to the many Shape classes that
may exist in your application. So it can be easily extended by adding
new sub classes of shape.
Regards
Andreas
-- Gwynne, Daughter of the Code
"This whole world is an asylum for the incurable."
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden