1.CADisplayLink
CADisplayLink Class,這個 Class 的功能類似於 Timer。由於能支援每秒高達 60 fps 的畫面同步功能,所以更適合用在製作遊戲動畫上面,相較之下 Timer 較常使用在背景處理層面,其基本使用方式如下。
//自行定義的函式,用來設定使用CADisplayLink的相關參數
-(void)initializeTimer {
//theTimer是CADisplayLink型態的指標,用來存放當前的設定狀態
theTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(countTotalFrames)];
//CADisplayLink內定值就是每秒60張(參數=1),參數=2就是每秒30張,以此類推
double fps = 60 / theTimer.frameInterval;
fpsLabel.text = [NSString stringWithFormat:@"%0.1f" , fps];
//設定執行狀態並啟動theTimer
[theTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
如同 Timer / 計時器一樣,selector 是設定每次觸發時所需要呼叫的函式,其寫法如下。
-(void)countTotalFrames {
frameCount ++;
framesLabel.text = [NSString stringWithFormat:@"%d", frameCount];
}
2.CAScrollLayer
使用cascrolllayer可以实现:通过改变一个layer的origin坐标,显示它的一部分内容.它的maskstobounds属性一般设为yes,这样就只能看见它的bounds内的内容.可以通过调用cascrolllayer本身的函数或者调用它的sublayer函数实现layer的滚动功能
3.CATextlayer
CATextLayer可以直接支持NSAttributedString!
CATextLayer代码:
CATextLayer *lary = [CATextLayer layer];
lary.string = @"dasfasa";
lary.bounds = CGRectMake(0, 0, 320, 20);
lary.font = @"HiraKakuProN-W3"; //字体的名字 不是 UIFont
lary.fontSize = 12.f; //字体的大小
lary.alignmentMode = kCAAlignmentCenter;//字体的对齐方式
lary.position = CGPointMake(160, 410);
lary.foregroundColor = [UIColor redColor].CGColor;//字体的颜色
[self.view.layer addSublayer:lary];
4.CATiledLayer
用于显示复杂的图片,以碎片的形式进行异步加载。
原文出处:http://www.cocoachina.com/bbs/read.php?tid-31201.html
demon:http://www.cocoachina.com/bbs/read.php?tid=31132
levelsOfDetail是指,从UIScrollView的1倍zoomScale开始,能够支持细节刷新的缩小级数。每一级是上一级的1/2,所以假设levelsOfDetail = n,levelsOfDetailBias不指定的话,CATiledLayer将会在UIScrollView的zoomScale为以下数字时重新drawLayer
2^-1 -> 2^-2 -> ... -> 2^-n
也就是
1/2, 1/4, 1/8, 1/16, ... , 1/2^n
在levelsOfDetailBias不指定的情况下,zoomScale大于0.5后就不会再drawLayer,所以若继续放大UIScrollView的话,画面将越来越模糊。
这个时候levelsOfDetailBias就有用了。
levelsOfDetailBias = m表示,将原来的1/2,移到2^m倍的位置。
假设levelsOfDetail = n,levelsOfDetailBias = m的话,会有如下队列:
2^m * 2^-1 -> 2^m * 2^-2 -> ... -> 2^m * 2^-n
简化一下即
2^(m - 1) -> 2^(m - 2) -> 2^(m - 3) ->... -> 2^(m - n)
举例,levelsOfDetail = 3,levelsOfDetailBias = 3,则你的UIScrollView将会在以下zoomScale时drawLayer
2^(3 - 1) -> 2^(3 - 2) -> 2^(3 - 3)
即4 -> 2 -> 1
特例是,levelsOfDetailBias > levelsOfDetail时,则每相差2倍就会drawLayer一下。
可以简单理解成:
levelsOfDetail表示一共有多少个drawLayer的位置
levelsOfDetailBias表示比1大的位置里有多少个drawLayer的位置(包括1)
5.CAShapeLayer
利用CAShapeLayer可以制作出任意的几何图形,其一是把它作为UIImageView的遮罩,达到把图片做成圆形效果。
//创建个人主页头部的用户头像
self.userHead = [[UIImageView alloc]initWithFrame:CGRectMake(10, 35, 80, 80)];
self.userHead.image = [UIImage imageNamed:@"start.jpg"];
//创建圆形遮罩,把用户头像变成圆形
UIBezierPath* path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(40, 40) radius:40 startAngle:0 endAngle:2*M_PI clockwise:YES];
CAShapeLayer* shape = [CAShapeLayer layer];
shape.path = path.CGPath;
self.userHead.layer.mask = shape;
[self addSubview:self.userHead];
6.CAReplicatorLayer
详情参考:http://tuohuang.info/14.html#.U4WdYZSSzf0
它自己能够重建包括自己在内的n个copies,这些copies是原layer中的所有sublayers,并且任何对原layer的sublayers设置的transform是可以积累的(accumulative). 基本上这样的一个关系:我们首先会重建一个CAReplicatorLayer实例,作为我们的sourceLayer, 这个sourceLayer我们需要一份copy,那包括自己在内就是2; 所以我们设置了它的instantCount = 2;这个是包括自己在内总共为2. 然后我们将SourceLayer的宽度设置为image的宽度,但是将其高度设置为image.size.height * 1.5; 并且在sourcelayer上加上masksToBounds为true的属性,这样一来我们可以保证超出的倒影部分会cut调一半,加上sourceLayer上正常的image,刚刚好组成了我们的完整的倒影。我们sourceLayer的sublayer就是_imageLayer,。但是我们只是单纯设置instantCount = 2的话, 那个_imageReplicatorLayer(这个就指代的是copy过来的第一个变量)是会继承sourceLayers中_imagelayer的Geometry,所以它两是重合的。那么我们必须做出transform, CARepliatorLayer有一个属性叫做instantTransform,这个属性指定了除了原来copy之外所有replication layer的trasnform规则,重要的是它是递增的。比如我们这里需要将imageReplicatorLayer应该往下移动image的高度,这一样来可以保证它是刚刚好在原来imagelayer的正下方,就跟倒影一样。 但是不一样的地方是:这个复制的imageReplicatorLayer它不是正常的,它是需要倒过来的,所以我们在transform上使用了 transform = CATransform3DScale(transform, 1.0, -1.0, 1.0); 这一个的意思是大小不变,但是y轴倒过来,这个应用到imageReplicatorLayer的坐标系是y轴朝上。 这样以来你就不能单纯是向原来一样移动image.height了, 因为y轴反了过来,所以你应该是 -2 * image.size.height 这样以来就搞定了。 最后我们给它加了一个渐变层,让它看起来更接近倒影的感觉。
- (void)viewDidLoad
{
[super viewDidLoad];
UIView *view = [self view];
//
// Yes, this is a very long method. I find it easier to explain what is happening by
// keeping the code in a single location (instead of breaking it up over multiple methods).
//
// Load the image to "reflect"
UIImage *image = [UIImage imageNamed:@"american-flag"];
// The replicator layer is where all of the magic happens
CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer];
[replicatorLayer setContentsScale:[[UIScreen mainScreen] scale]];
// The replicator layer's height is 1.5 times the size of the image. This means that
// we will effectively clip/ fade out our "reflection".
//
// ******** <- any y-flipping is performed along this plane
// * %% *
// * * image height
// * ^^ *
// ********
// ========
// = ^^ = + half height (mask to bounds effectively clips the reflected image)
// = =
//
// = total height of layer
[replicatorLayer setBounds:CGRectMake(0.0, 0.0, [image size].width, [image size].height * 1.5)];
// This ensures that the replicated image is clipped to the replicator's height
[replicatorLayer setMasksToBounds:YES];
// Position the replicator layer at the top of the view
// - use the x center point to make the math easy (place in center of view)
// - use the y upper point to position the layer 10 points below the top of the view (just a little bit of padding)
[replicatorLayer setAnchorPoint:CGPointMake(0.5, 0.0)];
[replicatorLayer setPosition:CGPointMake(view.frame.size.width / 2.0, 80.0)];
// We need two instances:
// 1) the main image layer
// 2) a replicated layer for the reflection
[replicatorLayer setInstanceCount:2];
// Create a transform used by the replicator layer to "flip" and position our reflected layer below the original image
//
// I will see if I can explain this.
// For clarity... we start with an identity
CATransform3D transform = CATransform3DIdentity;
//
// @******* <- this is the top of the replicator layer (the X,Y origin is at the @, with Y going down)
// * %% *
// * *
// * ^^ *
// ********
//
//
// Apply a negative scale to y (effectively flips)
//
// For example, hold your right hand in front of your face (knuckles facing you, thumb down). Now flip your
// hand up keeping your pinky finger in place (i.e. your pinky is a hinge).
//
// ======== <- will draw a flipped version up here
// = ^^ =
// = =
// = %% =
// ========
// ******** <- the "flip" is performed along here
// * %% *
// * * image height
// * ^^ *
// ********
transform = CATransform3DScale(transform, 1.0, -1.0, 1.0);
// translate down by 2x height to position the "flipped" layer below the main layer
// - 2x moves the flipped image under the main image giving us the "reflection"
//
// ******** <- y plane (any flipping is performed along this plane)
// * %% *
// * * image height
// * ^^ *
// ********
// ========
// = ^^ =
// = = <-- Remember: only half of the "relection" layer renders because the replicator layer clips to bounds.
// = %% =
// ========
transform = CATransform3DTranslate(transform, 0.0, -[image size].height * 2, 1.0);
[replicatorLayer setInstanceTransform:transform];
// Next we create a layer that displays the American flag image.
_imageLayer = [CALayer layer];
[_imageLayer setContentsScale:[[UIScreen mainScreen] scale]];
[_imageLayer setContents:(__bridge id)[image CGImage]];
[_imageLayer setBounds:CGRectMake(0.0, 0.0, [image size].width, [image size].height)];
[_imageLayer setAnchorPoint:CGPointMake(0.0, 0.0)];
[replicatorLayer addSublayer:_imageLayer];
// Finally overlay a gradient layer on top of the "reflection" layer.
CAGradientLayer *gradientLayer = [CAGradientLayer layer];
[gradientLayer setContentsScale:[[UIScreen mainScreen] scale]];
[gradientLayer setColors:@[
(__bridge id)[[[UIColor whiteColor] colorWithAlphaComponent:0.25] CGColor],
(__bridge id)[[UIColor whiteColor] CGColor]
]];
// Remember that the reflected layer is half the size, which is why the height of the gradient layer is cut in half.
[gradientLayer setBounds:CGRectMake(0.0, 0.0, replicatorLayer.frame.size.width, [image size].height * 0.5 + 1.0)];
[gradientLayer setAnchorPoint:CGPointMake(0.5, 0.0)];
[gradientLayer setPosition:CGPointMake(view.frame.size.width / 2, [image size].height + 80.0)];
[gradientLayer setZPosition:1]; // make sure the gradient is placed on top of the reflection.
[[view layer] addSublayer:replicatorLayer];
[[view layer] addSublayer:gradientLayer];
// One final (and fun step):
// Create a text layer that is a sublayer of the image layer.
// Core Animation will animate the text in all replicated layers. VERY COOL!!
CATextLayer *textLayer = [CATextLayer layer];
[textLayer setContentsScale:[[UIScreen mainScreen] scale]];
[textLayer setString:@"U.S.A."];
[textLayer setAlignmentMode:kCAAlignmentCenter];
CGFloat height = [(UIFont *)[textLayer font] lineHeight];
[textLayer setBounds:CGRectMake(0.0, 0.0, [_imageLayer frame].size.width, height)];
[textLayer setPosition:CGPointMake([_imageLayer frame].size.width / 2.0, [_imageLayer frame].size.height - 25.0)];
[textLayer setAnchorPoint:CGPointMake(0.5, 0.5)];
[_imageLayer addSublayer:textLayer];
// When the user taps, start _animating the image's text layer up and down.
[view setUserInteractionEnabled:YES];
[view setMultipleTouchEnabled:YES];
[view addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(animateTextLayer:)]];
}
- (void)animateTextLayer:(UIGestureRecognizer *)recognizer
{
CALayer *textLayer = (CALayer *)[[_imageLayer sublayers] objectAtIndex:0];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.y"];
CGFloat halfBoxHeight = [textLayer frame].size.height / 2.0;
[animation setFromValue:@([textLayer frame].origin.y + halfBoxHeight)];
[animation setToValue:@(halfBoxHeight)];
[animation setDuration:3.0];
[animation setRepeatCount:MAXFLOAT];
[animation setAutoreverses:YES];
[textLayer addAnimation:animation forKey:nil];
}
7.CATransaction 事务类,可以对多个layer的属性同时进行修改.它分隐式事务,和显式事务.
区分隐式动画和隐式事务:隐式动画通过隐式事务实现动画 。
区分显式动画和显式事务:显式动画有多种实现方式,显式事务是一种实现显式动画的方式。
->隐式事务
除显式事务外,任何对于CALayer属性的修改,都是隐式事务.这样的事务会在run-loop中被提交.
- (void)viewDidLoad {
//初始化一个layer,添加到主视图
layer=[CALayer layer];
layer.bounds = CGRectMake(0, 0, 200, 200);
layer.position = CGPointMake(160, 250);
layer.backgroundColor = [UIColor redColor].CGColor;
layer.borderColor = [UIColor blackColor].CGColor;
layer.opacity = 1.0f;
[self.view.layer addSublayer:layer];
[super viewDidLoad];
}
-(IBAction)changeLayerProperty
{
//设置变化动画过程是否显示,默认为YES不显示
[CATransaction setDisableActions:NO];
//设置圆角
layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
//设置透明度
layer.opacity = (layer.opacity == 1.0f) ? 0.5f : 1.0f;
}
->显式事务
通过明确的调用begin,commit来提交动画
修改执行时间
[CATransaction begin];
//显式事务默认开启动画效果,kCFBooleanTrue关闭
[CATransaction setValue:(id)kCFBooleanFalse
forKey:kCATransactionDisableActions];
//动画执行时间
[CATransaction setValue:[NSNumber numberWithFloat:5.0f] forKey:kCATransactionAnimationDuration];
//[CATransaction setAnimationDuration:[NSNumber numberWithFloat:5.0f]];
anotherLayer.cornerRadius = (anotherLayer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
layer.opacity = (layer.opacity == 1.0f) ? 0.5f : 1.0f;
[CATransaction commit];
->事物嵌套
事务嵌套
[CATransaction begin];
[CATransaction begin];
[CATransaction setDisableActions:YES];
layer.cornerRadius = (layer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
[CATransaction commit];
//上面的动画并不会立即执行,需要等最外层的commit
[NSThread sleepForTimeInterval:10];
//显式事务默认开启动画效果,kCFBooleanTrue关闭
[CATransaction setValue:(id)kCFBooleanFalse
forKey:kCATransactionDisableActions];
//动画执行时间
[CATransaction setValue:[NSNumber numberWithFloat:10.0f] forKey:kCATransactionAnimationDuration];
//[CATransaction setAnimationDuration:[NSNumber numberWithFloat:5.0f]];
anotherLayer.cornerRadius = (anotherLayer.cornerRadius == 0.0f) ? 30.0f : 0.0f;
[CATransaction commit];
8. CATransform3D
-
struct CATransform3D
-
{
-
CGFloat m11(x缩放), m12(y切变), m13(), m14() ;
-
CGFloat m21(x切变), m22(y缩放), m23(), m24() ;
-
CGFloat m31(), m32(), m33(), m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果。当然,z方向上得有变化才会有透视效果) ;
-
CGFloat m41(x平移), m42(y平移), m43(z平移), m44() ;
-
} ;
CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
[pulseAnimation setDuration:_animationDuration];
[pulseAnimation setRepeatCount:MAXFLOAT];
// The built-in ease in/ ease out timing function is used to make the animation look smooth as the layer
// animates between the two scaling transformations.
[pulseAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
// Scale the layer to half the size
//CATransform3D transform_1 = CATransform3DIdentity;//CATransform3DMakeScale(1.5, 1.5, 1.0);
CATransform3D transform = CATransform3DMakeRotation((M_PI/180*180), 1, 0, 1);
transform.m34 = 0.5;
// Tell CA to interpolate to this transformation matrix
[pulseAnimation setToValue:[NSValue valueWithCATransform3D:transform]];
// Tells CA to reverse the animation (e.g. animate back to the layer's transform)
[pulseAnimation setAutoreverses:_autoreverses];
// Finally... add the explicit animation to the layer... the animation automatically starts.
[_layer addAnimation:pulseAnimation forKey:kBTSPulseAnimation];
9.CAValueFunction
动画类型:平移、缩放、旋转
如把一个对象旋转180度可以使用一下方式:
CABasicAnimation * rotationAni = [CAAnimation animation];
CAValueFunction * valuFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ];
[rotationAni setFromValue:0];
[rotationAni setToValue:@(M_PI)];
[rotationAni setValueFunction:valuFunction];
10.CAEmitterCell、CAEmitterLayer 实现粒子效果
利用Core Animation、CAEmitterCell 以及 CAEmitterLayer在iOS5中实现各种粒子动画效果,包括雪花、火焰、烟雾、飘动的花瓣、爆炸等效果。
属性详解请参考:http://guxiaojje.blog.163.com/blog/static/1409422912012813104917788/
- (void) viewDidLoad
{
[super viewDidLoad];
// Configure the particle emitter
self.heartsEmitter = [CAEmitterLayer layer];
self.heartsEmitter.emitterPosition = CGPointMake(likeButton.frame.origin.x + likeButton.frame.size.width/2.0,
likeButton.frame.origin.y + likeButton.frame.size.height/2.0);//放射源的位置
self.heartsEmitter.emitterSize = likeButton.bounds.size;//放射源的大小
// Spawn points for the hearts are within the area defined by the button frame
self.heartsEmitter.emitterMode = kCAEmitterLayerVolume;//放射源的模式
self.heartsEmitter.emitterShape = kCAEmitterLayerRectangle;//放射源的形状
self.heartsEmitter.renderMode = kCAEmitterLayerAdditive;//放射源的渲染模式
// Configure the emitter cell
CAEmitterCell *heart = [CAEmitterCell emitterCell];//发射的粒子
heart.name = @"heart";
heart.emissionLongitude = M_PI/2.0; // up 粒子在xy平面内发射的方向
heart.emissionRange = 0.55 * M_PI; // in a wide spread 发射的水平方向的范围
heart.birthRate = 0.0; // emitter is deactivated for now 粒子再生的速度,0就是不会再生
heart.lifetime = 10.0; // hearts vanish after 10 seconds
heart.velocity = -120; // particles get fired up fast 初始速度是-120 向上
heart.velocityRange = 60; // with some variation
heart.yAcceleration = 20; // but fall eventually
heart.contents = (id) [[UIImage imageNamed:@"DazHeart"] CGImage];
heart.color = [[UIColor colorWithRed:0.5 green:0.0 blue:0.5 alpha:0.5] CGColor];
heart.redRange = 0.3; // some variation in the color
heart.blueRange = 0.3;
heart.alphaSpeed = -0.5 / heart.lifetime; // fade over the lifetime
heart.scale = 0.15; // let them start small
heart.scaleSpeed = 0.5; // but then 'explode' in size
heart.spinRange = 2.0 * M_PI; // and send them spinning from -180 to +180 deg/s
// Add everything to our backing layer
self.heartsEmitter.emitterCells = [NSArray arrayWithObject:heart];
[self.view.layer addSublayer:heartsEmitter];
}
- (void) viewWillUnload
{
[super viewWillUnload];
[self.heartsEmitter removeFromSuperlayer];
self.heartsEmitter = nil;
}
- (BOOL) shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIDeviceOrientationPortrait);
}
// ---------------------------------------------------------------------------------------------------------------
#pragma mark -
#pragma mark Interaction
// ---------------------------------------------------------------------------------------------------------------
- (IBAction) likeButtonPressed:(id)sender
{
// Fires up some hearts to rain on the view
CABasicAnimation *heartsBurst = [CABasicAnimation animationWithKeyPath:@"emitterCells.heart.birthRate"];
heartsBurst.fromValue = [NSNumber numberWithFloat:150.0];//喷出的粒子的数量
heartsBurst.toValue = [NSNumber numberWithFloat: 0.0];
heartsBurst.duration = 5.0;
heartsBurst.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
[self.heartsEmitter addAnimation:heartsBurst forKey:@"heartsBurst"];
}