媒体层图形技术之Core Animation 学习笔记

 

1.CADisplayLink

 

//自行定義的函式,用來設定使用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可以直接支持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

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)

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

使用CAReplicatorLayer重建动态的倒影

它 自己能够重建包括自己在内的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];

}


媒体层图形技术之Core Animation 学习笔记

7. 区分隐式动画和隐式事务:隐式动画通过隐式事务实现动画 。

区分显式动画和显式事务:显式动画有多种实现方式,显式事务是一种实现显式动画的方式。


->隐式事务
除显式事务外,任何对于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

 

{
  • ;
  • CGFloat m21(x切变), m22(y缩放), m23(), m24();
  1. ;
  2. CGFloat m41(x平移), m42(y平移), m43(z平移), m44();
  • } ;

首先要实现view(layer)的透视效果(就是近大远小),是通过设置m34的:

 

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];


媒体层图形技术之Core Animation 学习笔记媒体层图形技术之Core Animation 学习笔记

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"]; 

}


媒体层图形技术之Core Animation 学习笔记媒体层图形技术之Core Animation 学习笔记


你可能感兴趣的:(animation)