Core Animation

In a view hierarchy, sibling views typically do not have to overlapping bounds. For instance, imagine a view with two subviews that are buttons. It would confuse and frustrate the user when buttons are overlapping and obscuring each other.

The layer hierarchy, however, is a different story. Siblings are far more likely to overlap because layers are about visual effects and drawing, not user interaction.

Each layer has a property called zPosition. If two layers are siblings and they overlap, the layer with the higher zPosition is composited on top of the layer with the lower zPosition. ( A sublayer always draws on top of its superlayer, regardless of zPosition.)

 

All the animation happens on a background thread, this means the user interface isn't blocked when the animation runs.

What is a Layer?

CALayer is the model class for layer-tree objects. It encapsulates the position, size, and transform of a layer, which defines its coordinate system. It also encapsulates the duration and pacing of a layer and its animations by adopting the CAMediaTiming protocol which defines a layer's time space.

The CALayer simply contains the data(model) that is relevant to all the layer's attributes such as background color, border width, position,size,transform, and such.

CAScrollLayer

This layer enables you to scroll content that is larger than the viewpoint of the containing view.

CATiledLayer

This layer enables zooming and panning of content that is larger than the viewpoint of the containing view.

Wht's a Layer for?

building block for creating complex animations.

There are actually two basic categories for animation:

  • View animation, which is primarily used when you want to give your user interface some visual cues.
  • Layer animation, which is more commonly used for application content and functionality.

Layers do not receive events such as clicks and key presses. You need to capture the event at the backing view level and then pass it on to the layer.

Animating the Background color from Red to Green

- (CABasicAnimation *) backgroundColorAnimation
{
CABasicAnimation * anim = [CABasicAnimation animationWithKeyPath:@"backgroundColor"];

[anim setDuration:5.0];

[anim setFromValue:(id)[[UIColor redColor] CGColor]];
[anim setToValue:(id)[[UIColor greenColor] CGColor]];

return anim;
}

Center the layer in its parent view// how frame property is useful here!!! 

NSRect parentViewRect = [[window contentView] frame];
[layer setPosition: CGPointMake(parentView.size.width/2.0,parentView.size.height/2.0)]; 

Content

The content field of a layer is set using an image, specifially a CGImageRef. If you use a CAKeyframeAnimation to animate this field, you can create a simple slideshow application with a minimal amount of code. You can create an array of CGImageRef objects and set that array as your animation's values field.

contentsRect: Think of the contentsRect property as a view port of the layer contents.

Masking

Layers provide a way to mask their contents using masking fields.

mask 

The mask property is itself a layer. The opacity of the mask layer determines how the effect renders. When you specify a mask, keep in mind that the mask bounds determine what is allowed to show through rather than what is blocked from view.

masksToBounds

It is particularly useful when you have set a corner radius on a layer with content and want to ensure that the content doesn't spill to the outside of the content rectangle where the rounded corners are.

 Basic Animations

The animation proxy object

The animation proxy object is available in both NSView and NSWindow. It implements the protocol NSAnimatablePropertyContainer. This container uses Key-Value Coding to set the actual value of whatever parameter was specified while doing the value interpolation and animation behind the scenes.

let's look to how to use the animator proxy.

[[window animator] setFrame:newFrame display:YES];

By default, the animation plays back over the course of 0.25 seconds.

[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:5.0f];
[[window animator] setFrame:newFrame display:YES];
[NSAnimationContext endGrouping];

or adding an animation to the window animations dictionary.

CABasicAnimation *animation =
[CABasicAnimation animationWithKeyPath:@”frame”];
[animation setFromValue:[NSValue valueWithRect:oldFrame]];
[animation setToValue:[NSValue valueWithRect:newFrame]];
[animation setDuration:5.0f];
[window setAnimations:[NSDictionary animation forKey:@”frame”]];
[[window animator] setFrame:newFrame display:YES];

explicitly animating frame origin and size

CABasicAnimation *originAnimation = [CABasicAnimation animationWithKeyPath:@”frameOrigin”];
[originAnimation setFromValue:[NSValue valueWithPoint:oldImageFrame.origin]];
[originAnimation setToValue:[NSValue valueWithPoint:newFrame.origin]];
[originAnimation setDuration:5.0];
CABasicAnimation
*sizeAnimation = [CABasicAnimation animationWithKeyPath:@”frameSize”]; [sizeAnimation setFromValue: [NSValue valueWithSize:oldImageFrame.size]]; [sizeAnimation setToValue:[NSValue valueWithSize:newFrame.size]]; [sizeAnimation setDuration:5.0];
[[view animator] setAnimations:[NSDictionary dictionaryWithObjectsAndKeys:originAnimation, @”frameOrigin”, sizeAnimation, @”frameSize”, nil]]; [[view animator] setFrame:newFrame];

explicitly disabling layer animation

[CATransaction begin]
[CATransaction setValue:[NSNumber numberWithBool:YES]
                forKey: kCATransactionDisableActions]
[layer setBounds:bounds];
[CATransaction commit];

set animation duration in a layer

[CATransaction begin]
[CATransaction setValue:[NSNumber numberWithFloat:5.0f]
                 forKey: kCATransactionAnimationDuration]
[layer setBounds:bounds];
[CATransaction commit];

explicitly animating the layer bounds property

CABasicAnimation *boundsAnimation = [CABasicAnimation animationWithKeyPath:@”bounds”];
[boundsAnimation setFromValue:[NSValue valueWithRect:oldRect]];
[boundsAnimation setToValue:[NSValue valueWithRect:newRect]];
[boundsAnimation setDuration:5.0f];
[layer setBounds:NSRectToCGRect(newRect)];//NOT setFrame
[layer addAnimation:boundsAnimation forKey:@”bounds”];

the frame field of the layer is a derived value - calculated from the position, bounds, anchorpoint, and transform properties. This means that although you can set the frame explicitly, it will not animate. If you want to animate the size of the layer's rectangle, use bounds as your keypath. If you want to move and resize the layer at the same time, create two animations, one to animate the bounds, and one to animate the position.

 

Using CABasicAnimation

CABasicAnimation *animation = 
[CABasicAnimation animationWithKeyPath:@”position”];
[animation setFromValue:[NSValuevalueWithPoint:startPoint]];
[animation setToValue:[NSValuevalueWithPoint:endPoint]];
[animation setDuration:5.0];
[layer setPosition:endpoint];
[layer addAnimation:animation forKey:nil];

Notice that the forKey: parameter of the call is set to nil. This is the reason why the animation is not overriding the default. If you change the last line to forKey:@"position", the animation will work using the duration as expected. This tells the layer to use the new animation we have specified for this keypath whenever it needs to animated.

We can use the CATransaction class to override the default duration.

[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:5.0]
                 forKey:kCATransactionAnimationDuration];
[layer setPosition:endPoint];
[CATransaction commit];

Using animation group

Let’s say that we would prefer that, rather than having all our animations play simultane-ously, we want them to play back sequentially—one following the previous. We can achieve this by using a group animation

We must explicitly specify the duration of our animation group so that the time for each individual animation can be split up accordingly. In our example, we set our duration of the animation group to last 15 seconds and get each of our individual animations to play back for 5 seconds.

- (IBAction)animate:(id)sender;
{
NSRect oldRect = NSMakeRect(0.0, 0.0, 100.0, 100.0);
NSRect newRect = NSMakeRect(0.0, 0.0, 300.0, 300.0);
CABasicAnimation*boundsAnimation = [CABasicAnimation animationWithKeyPath:@”bounds”];
[boundsAnimation setFromValue:[NSValuevalueWithRect:oldRect]];
[boundsAnimation setToValue:[NSValuevalueWithRect:newRect]];
[boundsAnimation setDuration:15.0f];
[boundsAnimation setBeginTime:0.0f];
CABasicAnimation*positionAnimation = [CABasicAnimation animationWithKeyPath:@”position”];
[positionAnimation setFromValue: [NSValuevalueWithPoint: NSPointFromCGPoint([layer position])]];
[positionAnimation setToValue: [NSValuevalueWithPoint:NSMakePoint(0.0, 0.0)]];
[positionAnimation setDuration:15.0f];
[positionAnimation setBeginTime:5.0f];
CABasicAnimation*borderWidthAnimation = [CABasicAnimation animationWithKeyPath:@”borderWidth”];
[borderWidthAnimation setFromValue:[NSNumber numberWithFloat:5.0f]];
[borderWidthAnimation setToValue:[NSNumber numberWithFloat:30.0f]];
[borderWidthAnimation setDuration:15.0f];
[borderWidthAnimation setBeginTime:10.0f];

CAAnimationGroup
*group = [CAAnimationGroup animation]; [group setDuration:15]; [group setAnimations: [NSArray arrayWithObjects:boundsAnimation,positionAnimation,borderWidthAnimation, nil]]; [layer addAnimation:group forKey:nil]; }

 

 

 

 

 

posted on 2012-06-17 21:03  grep  阅读(731)  评论(0编辑  收藏  举报