CoreAnimation 小结


1 动画主体

在游戏中,动画的主体基本上是各种精灵 (Spirit),如主人公、敌人、子弹等等。而在 iOS 系统中,各种动画的主体就是 UIViewCALayer

UIView : 是各种控件的基类,用于显示内容,也处理各种点击、手势操作。可以通过在 ViewController 的根 UIView 下嵌入各种 UIView 来形成一个场景树,也就是 APP 用户看到的一个页面。

CALayer : 和 UIView 的特征非常相似,是一个矩形方块,用于显示内容 (如图片、文本等);也可以相互组合形成一颗场景树;一个很大的区别就是,CALayer 并不接受用户的交互,同时 UIView 包含一个 CALayer 的属性。

CALayer 在功能上是主要用于显示的,也提供了丰富的属性用于动画的执行,如背景颜色、3D 模型变换矩阵、位置、透明度等等。因此在 CoreAnimation 中,大部分的动画都是在 CALayer 上执行的。

一个 CALayer 分别拥有一个 modelLayer 和 一个 presentationLayer 属性,动画执行期间通过更新 presentationLayer 来显示动画效果,动画结束的时候通过 modelLayer 来显示动画的结果。

至于苹果官方为什么设计出 UIViewCALayer 2个看似有些类似的 class,可以参看 你给我解析清楚,都有了CALayer了,为什么还要UIView,该文讲述了CALayer和UIView各自的必要性以及苹果设计上考虑的周全性。

2 属性动画

2.1 CABasicAnimation

先直接来看一段示例代码


CABasicAnimation *anim = [CABasicAnimation animation];
    // 设置动画的类型为“位移动画”
    anim.keyPath = @"position";
    // 设置动画的执行时间为 10 秒
    anim.duration = 10;
    // 设置位移动画开始的起点绝对位置
    anim.fromValue = [NSValue valueWithCGPoint:pointSrc];
    // 设置位移动画结束的终点绝对位置
    anim.toValue = [NSValue valueWithCGPoint:pointDes];
    
    // 设置位移动画结束的终点相对起点的位置
    //anim.byValue = [NSValue valueWithCGPoint:CGPointMake(10, 60)];

    // 若为true,动画在结束的时候,会自动从CALayer上移除 anim 对象;
    // 若为false,动画结束的时候需要程序猿手动调用 `removeAnimationForKey` 移除
    //anim.removedOnCompletion = NO;
    
    // 动画执行的回调对象
    //anim.delegate = self;
    
    // 动画重复执行的次数,若设置为 `HUGE_VALF` 可以认为是在无限循环
    //anim.repeatCount = HUGE_VALF; //2;
    
    // 在设置的时间内,动画重复执行,不能和 `repeatCount` 一起使用
    //anim.repeatDuration = 25;
    
    // 设置结束的时候,自动执行逆动画
    //anim.autoreverses = YES;

    // 设置动画开始时间,通过在 `CALayer` 当前时间上添加值,显示延迟或者提前启动动画
    //anim.beginTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil] + 5;
    
    // 设置动画的偏移时间
    //anim.timeOffset = 5;
    
    // 设置动画的执行速度,默认为 1
    //anim.speed = speed;
    
    // 设置动画执行的开始和结束,是否将 `presentationLayer` 的对应动画属性设置 `modelLayer`
    // 可选值有kCAFillModeRemoved, kCAFillModeBackwards, kCAFillModeForwards, kCAFillModeBackwards (默认)
    //anim.fillMode = kCAFillModeBoth;

    // 设置动画执行的时间轴,通俗的讲就是设置动画执行的各个时间的速率
    //anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    //anim.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.2 :0.2 :0.8 :0.8];

    // 加动画对象添加给 `CALayer`,并开始执行动画
    [self.button.layer addAnimation:anim forKey:nil];

这段实例代码涵盖了 CABasicAnimation 中可以设置的属性,注释中也给出了各个属性的意义

  • 示例 1 : 从左到右的动画的位移动画,且只执行一次
    CGPoint point = self.sunImageView.layer.position;
    CGPoint pointSrc = CGPointMake(point.x + 20, point.y);
    CGPoint pointDes = CGPointMake(pointSrc.x + 120, pointSrc.y);

    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:@"position"];
    anim.duration = 5;
    anim.fromValue = [NSValue valueWithCGPoint:pointSrc];
    anim.toValue = [NSValue valueWithCGPoint:pointDes];
image
  • 示例 2 : 设置重复的位移动画
    anim.repeatCount = HUGE_VALF;
    anim.autoreverses = true;
image
  • 示例 3 : 设置动画开始时间
    anim.beginTime=[self.button.layer 
        convertTime:CACurrentMediaTime() fromLayer:nil] - 4;
image
  • 示例 4 : 设置动画的偏移时间
    // anim.beginTime=[self.button.layer convertTime:CACurrentMediaTime() fromLayer:nil] - 4;
    anim.timeOffset = 4;
image
  • 示例 5 : 设置动画的速度
    anim.speed = 2;
image
  • 示例 6 : speedbeginTime 一起使用
    anim.speed = 2;
    anim.beginTime=[self.button.layer
        convertTime:CACurrentMediaTime() fromLayer:nil] - 1.5;
image
  • 示例 7 : speedtimeOffset 一起使用
    anim.speed = 2;
    anim.timeOffset = 1.5;
image
  • 示例 8 : 设置动画开始结束时的表现模式
    anim.fillMode = kCAFillModeRemoved;
    anim.beginTime=[self.button.layer convertTime:CACurrentMediaTime() fromLayer:nil] + 1.5;
image
    anim.fillMode = kCAFillModeBackwards;
    anim.beginTime=[self.button.layer convertTime:CACurrentMediaTime() fromLayer:nil] + 1.5;
image
  • 示例 9 : 设置动画执行的时间轴
    anim.timingFunction = [CAMediaTimingFunction 
        functionWithName:kCAMediaTimingFunctionEaseIn];
image
    anim.timingFunction = [CAMediaTimingFunction 
        functionWithControlPoints:0.5 :0.1 :0.5 :0.9];
image

说明

  1. toValuebyValue 不应该同时设置;

  2. repeatCount 指动画完整执行的次数,repeatDuration 指定在一段时间内动画能重复执行,如 duration 为 5,repeatCount 为 2,则等价于 repeatDuration 为 10;

  3. repeatCountrepeatDuration 不应该同时设置;

  4. 设置 beginTime 不为0,会延长或者缩短动画执行时间,但设置 timeOffset 会偏移的动画执行,但并不影响总的动画执行时间;

  5. speed 参数能加快或者减慢动画执行速度,会影响 duration 的表现值;如 示例 5 中,duration=5; speed = 2; 则动画真正的执行时间为 2.5 秒;

  6. 示例 6speedbeginTime 一起使用,beginTime 设置提前 1.5 秒,这里的 1.5 秒是相对动画动画真正的执行时间为 2.5 秒而言,而不是 duration 参数指定的 5 秒;

  7. 示例 7speedtimeOffset 一起使用,timeOffset 设置提前 1.5 秒,这里的 1.5 秒是相对 duration 参数指定的 5 秒,而不是动画真正的执行时间为 2.5 秒而言;

  8. 示例 8fillMode 的默认值为 kCAFillModeRemoved,在动画开始之前等待时间内,动画主体在原位置等待;当值为 kCAFillModeBackwards,动画主体在起点位置等待;当值为 kCAFillModeForwards,动画主体在终点位置等待;kCAFillModeBoth 动画主体分别在起点和终点位置等待

  9. 示例 9timingFunction 的默认值为 kCAMediaTimingFunctionLinear,为动画匀速执行;其他可选值有:kCAMediaTimingFunctionEaseIn (先慢后快), kCAMediaTimingFunctionEaseOut (先快后慢), kCAMediaTimingFunctionEaseInEaseOut (先慢后快再慢), kCAMediaTimingFunctionDefault (先慢后快); 也可以使用设置 3 次 4 控制点贝塞尔曲线的中间 2 个控制点位置设置

2.2 Transaction动画

2.2.1 显式Transaction动画
  • 示例 10 : 显式动画
[CATransaction begin];
[CATransaction setAnimationDuration:2.0];
    
[CATransaction setAnimationTimingFunction:
    [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault]];

// 动画执行结束时调用
[CATransaction setCompletionBlock:^{
    [CATransaction begin];
    [CATransaction setAnimationDuration:5.0];
        
    // 动画结束的时候,修改属性 2
        
    [CATransaction commit];
}];
   
// 修改属性 1

[CATransaction commit];
  • 修改属性 1
self.actionLayerView.layer.backgroundColor = [UIColor colorWithRed:1.0
                                                      green:0.0
                                                       blue:0.0
                                                      alpha:1.0].CGColor;
  • 动画结束的时候,修改属性 2
self.actionLayerView.layer.backgroundColor = [UIColor colorWithRed:0.0
                                                             green:1.0
                                                              blue:0.0
                                                             alpha:1.0].CGColor;
  • 执行结果
image
2.2.2 隐式Transaction动画
  • 示例 11 : 默认隐式动画
CGFloat red = arc4random() / (CGFloat)INT_MAX;
CGFloat green = arc4random() / (CGFloat)INT_MAX;
CGFloat blue = arc4random() / (CGFloat)INT_MAX;
    
self.actionLayerView.layer.backgroundColor = [UIColor colorWithRed:red
                                                             green:green
                                                              blue:blue
                                                             alpha:1.0].CGColor;
  • 执行结果
image

说明

  1. 直接对 UIView 内置 CALayer 进行设置背景颜色,其他并没有设置,但也能看到一个较快的动画效果,这个就是隐式动画
  2. 这里执行的动画效果是默认的动画效果,那如何能自定义隐式动画效果呢?

我们定义 CALayer 中的显示属性发生改变时所执行的动画为 actions,而系统中获取 action 的顺序如下:

  1. CALayer 设置了 delegate 属性,并且 delegate 中实现了 CALayerDelegate 中的 -actionForLayer:forKey,则通过调用该方法得到 action 值。

  2. 若�并没有设置 delegate 属性或者 CALayerDelegate 中并没有定义 -actionForLayer:forKey,则检查 CALayeractions 字典属性,获取 action 值。

  3. actions 并未定义,则检查 CALayerstyle 属性。

  4. style 属性并未定义,则 通过 + (id)defaultValueForKey:(NSString *)key 获取 action 值。

由上可知,上面代码的执行正是通过 + (id)defaultValueForKey:(NSString *)key 获取的 action 值。

  • 示例 12 : 自定义隐式动画
- (void)viewDidLoad
{
    [super viewDidLoad];

    CABasicAnimation *anim = [CABasicAnimation 
        animationWithKeyPath:@"backgroundColor"];
    anim.duration = 5;
    
    self.actionLayerView.layer.actions = @{@"backgroundColor":anim};
}

属性修改代码同 示例11

  • 执行结果
image

3 计时器控制动画

3.1 NSTimer 和 CADisplayLink 的使用

NSTimer 和 CADisplayLink 都能开启计时器,并在每次计时器的回调中设置显示属性

  • 示例 13 : NSTimer 动画
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //adjust anchor points
    self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
    self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);

    //start timer
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                  target:self
                                                selector:@selector(tick)
                                                userInfo:nil
                                                 repeats:YES];
    
    //set initial hand positions
    [self tick];
}

- (void)tick
{
    //convert time to hours, minutes and seconds
    NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
    NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
    NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
    
    //calculate hour hand angle
    CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;
    
    //calculate minute hand angle
    CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;
    
    //calculate second hand angle
    CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;
    
    //rotate hands
    self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);
    self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);
    self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);
}

  • 执行结果
image
  • 示例 14 : CADisplayLink 动画
- (void)animate
{
    //reset ball to top of screen
    self.ballView.center = CGPointMake(150, 32);
    
    //configure the animation
    self.duration = 1.0;
    self.timeOffset = 0.0;
    self.fromValue = [NSValue valueWithCGPoint:CGPointMake(150, 32)];
    self.toValue = [NSValue valueWithCGPoint:CGPointMake(150, 268)];
    
    //stop the timer if it's already running
    [self.timer invalidate];
    
    //start the timer
    self.lastStep = CACurrentMediaTime();
    self.timer = [CADisplayLink displayLinkWithTarget:self
                                             selector:@selector(step:)];
    //self.timer.frameInterval = 2;
    [self.timer addToRunLoop:[NSRunLoop mainRunLoop]
                     forMode:NSDefaultRunLoopMode];
}

- (void)step:(CADisplayLink *)timer
{
    //calculate time delta
    CFTimeInterval thisStep = CACurrentMediaTime();
    CFTimeInterval stepDuration = thisStep - self.lastStep;
    self.lastStep = thisStep;
    
    // 计算时间偏移
    self.timeOffset = MIN(self.timeOffset + stepDuration, self.duration);
    
    // 单位化time值
    float time = self.timeOffset / self.duration;
    
    // 重新计算time,球到起点的距离和行程的比值
    time = bounceEaseOut(time);
    
    // 通过差值计算新的位置
    id position = [self interpolateFromValue:self.fromValue
                                     toValue:self.toValue
                                        time:time];
    
    // 设置球的新位置
    self.ballView.center = [position CGPointValue];
    
    // 当动画时间到的时候,停止计时器
    if (self.timeOffset >= self.duration)
    {
        [self.timer invalidate];
        self.timer = nil;
    }
}

  • 执行结果
image

3.2 NSTimer 和 CADisplayLink 的对比

可以发现,使用 NSTimerCADisplayLink 都能实现相同的效果,并且编写的代码差别并不大。那么,二者之间有哪些差别呢?

  1. NSTimer 初始化器接受调用方法逻辑之间的间隔作为它的其中一个参数,预设一秒执行 30 次; CADisplayLink 是一个能让我们以和屏幕刷新率相同的频率将内容画到屏幕上的定时器 ( 60 /秒)。

  2. NSTimer 设置 timeInterval - 时间间隔; CADisplayLink通过 frameInterval 来设置几帧调用一次函数。

  3. NSTimer 一旦初始化它就开始运行; CADisplayLink 需要将显示链接添加到一个运行循环中。

  4. NSTimer 的精度低,NSTimer 的触发时间到的时候,runloop 如果在阻塞状态,触发时间就会推迟到下一个 runloop 周期。并且 NSTimer 新增了 tolerance 属性,让用户可以设置可以容忍的触发的时间的延迟范围; CADisplayLink 的精度高, CADisplayLink 在正常情况下会在每次刷新结束都被调用。于是我们不需要在格外关心屏幕的刷新频率了,因为它本身就是跟屏幕刷新同步的。

  5. NSTimerCADisplayLink 都能 add 进 run loop。都能设置优先级。

  6. NSTimer 使用范围要广泛的多,各种需要单次或者循环定时处理的任务都可以使用; CADisplayLink 的使用范围相对单一些,适合做 UI 的不停重绘,比如自定义动画引擎或者视频播放的渲染。

另外使用 CADisplayLink 添加至 run loop 的优先级有:

  1. NSDefaultRunLoopMode — 标准优先级

  2. NSRunLoopCommonModes — 优先级高于NSDefaultRunLoopMode

  3. UITrackingRunLoopMode — 用在UIScrollView和其他控件的动画

3.3 计时器动画的优缺点

  • 优点:

可以控制动画的每一帧内容,动画过程可以比较灵活,也可以在动画执行过程中可以交互控制动画

  • 缺点:

需要设计函数计算每一帧内容,动画过程中各个逻辑都需要用户编写

4 串行动画

因为 core animation 中并没有专门的类来定义串行动画 (至少我前面看的时候,还没发现),所以就根据自己的粗浅理解,如何来实现串行动画

  • 方式一
在animationDidStop:(CAAnimation*)anim finished:(BOOL)flag中触发下一个动画
  • 方式二
 在[UIView animateWithDuration:<#(NSTimeInterval)#>
                 animations:<#^(void)animations#>
             completion:<#^(BOOL finished)completion#>]
   中的completion函数中触发下一个动画

5 并行动画

方式一 CAAnimationGroup

CAAnimationGroup *groupAnimation = [CAAnimationGroup animation]; 
groupAnimation.animations = @[animation1, animation2];
[colorLayer addAnimation:groupAnimation forKey:nil];

其中 animation1 和 animation2 分别为位移动画和背景颜色动画

//create the position animation
CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
animation1.keyPath = @"position";
animation1.path = bezierPath.CGPath;
animation1.rotationMode = kCAAnimationRotateAuto;
    
//create the color animation
CABasicAnimation *animation2 = [CABasicAnimation animation];
animation2.keyPath = @"backgroundColor";
animation2.toValue = (__bridge id)[UIColor redColor].CGColor;

注意:groupAnimation中的speed,duration的优先级低于animation1和animation2中的speed,duration

  • 执行结果
image

方式二 在同一个layer中添加多于一个的animation

//create the position animation
CAKeyframeAnimation *animation1 = [CAKeyframeAnimation animation];
animation1.keyPath = @"position";
animation1.path = bezierPath.CGPath;
animation1.rotationMode = kCAAnimationRotateAuto;
    
//create the color animation
CABasicAnimation *animation2 = [CABasicAnimation animation];
animation2.keyPath = @"backgroundColor";
animation2.toValue = (__bridge id)[UIColor redColor].CGColor;

[colorLayer addAnimation:animation1 forKey:nil];
[colorLayer addAnimation:animation2 forKey:nil];

animation1和animation2中的speed或duration并不相互干涉

  • 执行结果
image

方式三

在 [UIView animateWithDuration:<#(NSTimeInterval)#>
                 animations:<#^(void)animations#>
             completion:<#^(BOOL finished)completion#>]
中的animations函数里面添加多个的目标属性

执行结果

image

6 帧动画

方式一 计时器控制帧动画

在计时器的响应函数中不断改变ImageView的 image 属性

-(void)timerHandler:(NSTimer *)timer
{
    if (playIndex>[self.frames count]-1) {
        playIndex=0;
    }
    
    self.image=[self.frames objectAtIndex:playIndex];
    playIndex++;
}

执行结果

image

方式二

catImageView.animationImages = [NSArray arrayWithObjects:
                    [UIImage imageNamed:@"cat_stand_0.png"],
                    [UIImage imageNamed:@"cat_stand_2.png"],nil];
[catImageView setAnimationDuration:1.0f];
[catImageView setAnimationRepeatCount:HUGE_VALF];
[catImageView startAnimating];

执行结果

image

6 Transition动画

方式一

// 新建左移进入的 Transition 动画对象
CATransition *transition = [CATransition animation];
transition.type = kCATransitionMoveIn;
transition.subtype = kCATransitionFromLeft;

// 为 ImageView 的内置 CALayer 添加 Transition 动画
[self.imageView.layer addAnimation:transition forKey:nil];
    
// 修改图片
UIImage *currentImage = self.imageView.image;
NSUInteger index = [self.images indexOfObject:currentImage];
index = (index + 1) % [self.images count];
self.imageView.image = self.images[index];

执行结果

image

方式二

[UIView transitionWithView:self.layerView
                      duration:2
                       options:UIViewAnimationOptionTransitionCurlDown
                    animations:^{
                        CGFloat red = arc4random() / (CGFloat)INT_MAX;
                        CGFloat green = arc4random() / (CGFloat)INT_MAX;
                        CGFloat blue = arc4random() / (CGFloat)INT_MAX;
                        self.colorLayer.backgroundColor = [UIColor colorWithRed:red
                                                                          green:green
                                                                           blue:blue
                                                                          alpha:1.0].CGColor;
                    } completion:^(BOOL finished) {
                         // 在动画结束时,执行逻辑
                    }];

执行结果

image

说明
options 属性 : 其他可选值有 UIViewAnimationOptionTransitionNone (default), UIViewAnimationOptionTransitionFlipFromLeft, UIViewAnimationOptionTransitionFlipFromRight, UIViewAnimationOptionTransitionCurlUp, UIViewAnimationOptionTransitionCurlDown, UIViewAnimationOptionTransitionCrossDissolve, UIViewAnimationOptionTransitionFlipFromTop, UIViewAnimationOptionTransitionFlipFromBottom;

感兴趣的同学可以自行去尝试查看效果

方式三

- (void)viewDidLoad
{
    [super viewDidLoad];

    //create sublayer
    self.colorLayer = [CALayer layer];
    self.colorLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
    self.colorLayer.backgroundColor = [UIColor blueColor].CGColor;
    
    //add a custom action
    CATransition *transition = [CATransition animation];
    transition.type = kCATransitionPush;
    transition.subtype = kCATransitionFromLeft;
    transition.duration = 1;
    //transition.repeatCount = 2;
    //transition.repeatDuration = 2;
    //transition.beginTime
    //transition.timeOffset
    //transition.timingFunction
    //transition.autoreverses = YES;
    //transition.removedOnCompletion = NO;   //invalid
    //transition.fillMode = kCAFillModeBoth; //invalid
    //transition.speed = 2;
    
    self.colorLayer.actions = @{@"backgroundColor": transition};
    
    //add it to our view
    [self.layerView.layer addSublayer:self.colorLayer];
}

- (IBAction)changeColor
{
    //randomize the layer background color
    CGFloat red = arc4random() / (CGFloat)INT_MAX;
    CGFloat green = arc4random() / (CGFloat)INT_MAX;
    CGFloat blue = arc4random() / (CGFloat)INT_MAX;
    self.colorLayer.backgroundColor = [UIColor colorWithRed:red
                                                      green:green
                                                       blue:blue
                                                      alpha:1.0].CGColor;
}

执行结果

type = kCATransitionPush

image

type = kCATransitionFade

image

type = kCATransitionMoveIn

image

type = kCATransitionReveal

image

其他属性前面在属性动画中已经讲述过,这边就不再赘述

7 粒子动画

Core Animation 中通过 CAEmitterLayerCAEmitterCell 来实现粒子动画

其中 CAEmitterLayerCALayer 的子类,是一个拥有高性能的例子系统的显示容器。通过定义不同类型的 CAEmitterCell 实例,并添加至 CAEmitterLayer 来显示如火焰、雪花等等的粒子效果

- (void) viewDidLoad
{
    [super viewDidLoad];
    
    CGRect viewBounds = self.view.layer.bounds;
    
    // 创建 emitter layer
    self.fireEmitter    = [CAEmitterLayer layer];
    
    // 设置粒子发射器的位置
    self.fireEmitter.emitterPosition = CGPointMake(viewBounds.size.width/2.0, viewBounds.size.height - 60);
    // 设置粒子发射器的尺寸
    self.fireEmitter.emitterSize    = CGSizeMake(45, 0);
    // 设置粒子从粒子发射器的形状外围生成
    self.fireEmitter.emitterMode    = kCAEmitterLayerOutline;
    // 设置粒子发射器的形状为直线
    self.fireEmitter.emitterShape   = kCAEmitterLayerLine;
    // 使用 `kCAEmitterLayerAdditive` 参数,使粒子重叠部分增加亮度,创建火焰中心“亮”的效果
    self.fireEmitter.renderMode     = kCAEmitterLayerAdditive;
    
    // 创建粒子发射单元
    CAEmitterCell* fire = [CAEmitterCell emitterCell];
    [fire setName:@"fire"];

    // 设置粒子创建的速度
    fire.birthRate          = 450;
    // 设置粒子的发射方向 (经度值)
    fire.emissionLongitude  = M_PI;
    // 设置粒子发射方向的(纬度值)
    //fire.emissionLatitude   = M_PI;
    // 设置粒子发射的初始速度
    fire.velocity           = -80;
    // 设置粒子发射的初始速度范围
    fire.velocityRange      = 30;
    // 设置粒子发射的方向角度范围
    fire.emissionRange      = 1.1;
    // 设置粒子发射后的 y 方向的加速度,火苗越向上越快
    fire.yAcceleration      = -200;
    // 设置粒子发射后的尺寸变化速度,火苗越来越小
    fire.scaleSpeed         = 0.3;
    // 设置粒子发射后的生命周期处置
    fire.lifetime           = 0.9;
    // 设置粒子发射后的生命周期范围
    fire.lifetimeRange      = 0.35;

    fire.color = [[UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:0.1] CGColor];
    // 设置粒子的内容图片
    fire.contents = (id) [[UIImage imageNamed:@"DazFire"] CGImage];
        
    // 将粒子发射器添加至 `CAEmitterLayer`
    self.fireEmitter.emitterCells   = [NSArray arrayWithObject:fire];
    // `CAEmitterLayer` 添加至场景树中
    [self.view.layer addSublayer:self.fireEmitter];
}

执行结果

image

8 总结

大概简单的总结了下 Core Animation 中定义的常用动画,当然还是有些属性和细节等还未介绍,感兴趣的 iOS 同学可以深入去了解下;

除此之外,还有其他的,如使用二维物理引擎实现的物理动画,使用 CAEAGLLayer 显示的OpenGL三位动画等,这里并没有介绍,以后可能会介绍吧O(∩_∩)O~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容