动画笔记

一、UIView基础动画

通过修改对应视图(UIView)的属性,可以实现一些最基础的动画效果.

  • 位置和尺寸的修改: bounds frame center transform
  • 外观样式的变化: backgroundColor alpha
示例1:改变UIView的frame
[UIView animateWithDuration:1.0 animations:^{
       self.imageView.left += 150;
   }];

与之对应的还有:

[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{
        self.imageView.left += 200;
    } completion:^(BOOL finished) { //动画执行完成操作
    }];
示例2、反复来回移动效果
[UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionRepeat | UIViewAnimationOptionAutoreverse animations:^{
        self.imageView.left += 150;
    } completion:^(BOOL finished) {
    }];
示例3、弹簧效果,可用于弹出框动画效果
//参数说明:usingSpringWithDamping 弹性阻尼系数取值0~1,值越大,弹框幅度越小 
//initialSpringVelocity:初始速度
[UIView animateWithDuration:1 delay:0.0 usingSpringWithDamping:0.5 initialSpringVelocity:0.7 options:UIViewAnimationOptionCurveEaseInOut animations:^{
       self.testButton.top -= 160;
   } completion:nil];
示例4 3D效果的转场动画
[UIView transitionWithView:self.imageView duration:1.0 options:UIViewAnimationOptionTransitionCurlUp animations:^{
        self.imageView.image = [UIImage imageNamed:@"6"];
    } completion:nil];

同理还有下面方法从一个view过渡到另一个view:

[UIView transitionFromView:self.imageView toView:self.imageView2 duration:1.0 options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished) {
    }];
示例5、动画组

在实际应用中,不可避免的需要将几个动画按照次序进行先后执行.

 [UIView animateKeyframesWithDuration: 4 delay: 0 options: UIViewKeyframeAnimationOptionCalculationModeLinear animations: ^{
        __block CGPoint center = self.imageView.center;
        [UIView addKeyframeWithRelativeStartTime: 0 relativeDuration: 0.1 animations: ^{
            self.imageView.center = (CGPoint){ center.x + 15, center.y + 80 };
        }];
        [UIView addKeyframeWithRelativeStartTime: 0.1 relativeDuration: 0.15 animations: ^{
            self.imageView.center = (CGPoint){ center.x + 45, center.y + 185 };
        }];
        [UIView addKeyframeWithRelativeStartTime: 0.25 relativeDuration: 0.3 animations: ^{
            self.imageView.center = (CGPoint){ center.x + 90, center.y + 295 };
        }];
        [UIView addKeyframeWithRelativeStartTime: 0.55 relativeDuration: 0.3 animations: ^{
            self.imageView.center = (CGPoint){ center.x + 180, center.y + 375 };
        }];
        [UIView addKeyframeWithRelativeStartTime: 0.85 relativeDuration: 0.15 animations: ^{
            self.imageView.center = (CGPoint){ center.x + 270, center.y + 435 };
        }];
        [UIView addKeyframeWithRelativeStartTime: 0 relativeDuration: 1 animations: ^{
            self.imageView.transform = CGAffineTransformMakeRotation(M_PI);
        }];
    } completion: nil];


以上5个示例中用到的参数options说明:

1、常规动画属性设置(可以同时选择多个进行设置):
     UIViewAnimationOptionLayoutSubviews:动画过程中保证子视图跟随运动。
     UIViewAnimationOptionAllowUserInteraction:动画过程中允许用户交互。
     UIViewAnimationOptionBeginFromCurrentState:所有视图从当前状态开始运行。
     UIViewAnimationOptionRepeat:重复运行动画。
     UIViewAnimationOptionAutoreverse :动画运行到结束点后仍然以动画方式回到初始点。
     UIViewAnimationOptionOverrideInheritedDuration:忽略嵌套动画时间设置。
     UIViewAnimationOptionOverrideInheritedCurve:忽略嵌套动画速度设置。
     UIViewAnimationOptionAllowAnimatedContent:动画过程中重绘视图(注意仅仅适用于转场动画)。
     UIViewAnimationOptionShowHideTransitionViews:视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画)
     UIViewAnimationOptionOverrideInheritedOptions :不继承父动画设置或动画类型。
2、 动画速度控制(可从其中选择一个设置)
     UIViewAnimationOptionCurveEaseInOut:动画先缓慢,然后逐渐加速。
     UIViewAnimationOptionCurveEaseIn :动画逐渐变慢。
     UIViewAnimationOptionCurveEaseOut:动画逐渐加速。
     UIViewAnimationOptionCurveLinear :动画匀速执行,默认值。
 3、转场类型(仅适用于转场动画设置,可以从中选择一个进行设置,基本动画、关键帧动画不需要设置)
     UIViewAnimationOptionTransitionNone:没有转场动画效果。
     UIViewAnimationOptionTransitionFlipFromLeft :从左侧翻转效果。
     UIViewAnimationOptionTransitionFlipFromRight:从右侧翻转效果。
     UIViewAnimationOptionTransitionCurlUp:向后翻页的动画过渡效果。
     UIViewAnimationOptionTransitionCurlDown :向前翻页的动画过渡效果。
     UIViewAnimationOptionTransitionCrossDissolve:旧视图溶解消失显示下一个新视图的效果。
     UIViewAnimationOptionTransitionFlipFromTop :从上方翻转效果。
     UIViewAnimationOptionTransitionFlipFromBottom:从底部翻转效果。

二、layer动画

View Animations可以实现一些简单的动效,但并不能够完全满足开发使用,自定义程度比较低,为此我们来学习下Layer Animations.
那么Layer有哪些可以自定义动画的属性呢?

  • 位置和尺寸: bounds position transform
  • 边框: borderColor borderWidth cornerRadius
  • 阴影: shadowOffset shadowOpacity shadowPath shadowRadius
  • 内容: contents mask opacity
    等等,以上仅仅只是一部分.
示例一:CABasicAnimation实现简单动画
    CABasicAnimation *ani = [CABasicAnimation animationWithKeyPath:@"position.x"];
    ani.fromValue = @(100);
    //结束位置
    ani.toValue = @(300);
    //持续时间
    ani.duration = 1.0;
    //延迟0.3秒执行
    ani.beginTime = CACurrentMediaTime() + 0.3; 
    [self.imageView.layer addAnimation:ani forKey:nil];

我们会看到动画执行完成会立刻回到初始状态,如果保持在结束状态添加下面代码即可:

// 保证fillMode起作用
    ani.removedOnCompletion = NO;
    // 动画结束后,layer会保持结束状态
    ani.fillMode = kCAFillModeForwards;

fillMode的几个值的分别代表的含义:

     kCAFillModeRemoved : 默认样式 动画结束后会回到layer的开始的状态
     kCAFillModeForwards : 动画结束后,layer会保持结束状态
     kCAFillModeBackwards : layer跳到fromValue的值处,然后从fromValue到toValue播放动画,最后回到layer的开始的状态
     kCAFillModeBoth : kCAFillModeForwards和kCAFillModeBackwards的结合,即动画结束后layer保持在结束状态

我们可以通过代理获取动画执行开始、结束时刻,秩序遵守CAAnimationDelegate即可
实现代码如下:

 // 设置名称  因为delegate方法中可能有多个CABasicAnimation设置了代理,根据name获取不同CABasicAnimation对象
    [ani setValue:@"form" forKey:@"name"];
    // 方便代理中可以拿到layer   CABasicAnimation对象可以作用于多个UIView,上一步获取CABasicAnimation对象,这一步获取作用于哪个View上
    [ani setValue:self.imageView.layer forKey:@"layer"];
    //设置代理可以知道动画开始、结束时间
    ani.delegate = self;

两个代理方法,在动画结束后做一个特效缩放操作

//CAAnimationDelegate
- (void)animationDidStart:(CAAnimation *)anim{
    NSLog(@"动画开始了");
}
//CAAnimationDelegate
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    NSString *animName = [anim valueForKey:@"name"];
    if (animName) {
        if ([animName isEqualToString:@"form"]) {//找到CABasicAnimation对象
            CALayer *layer = [anim valueForKey:@"layer"];//找到view的layer
            [anim setValue:nil forKeyPath:@"layer"];
            CABasicAnimation *pulse = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
            pulse.fromValue = @(1.25);
            pulse.toValue = @(1.0);
            pulse.duration = 3.25;
            [layer addAnimation:pulse forKey:nil];
            
        }
    }
}

在设计交互中,常常会碰到这样的一个问题,在动画的执行过程中,由于用户的点击操作,需要提前终止动画,该怎么实现呢?很简单

     // forKey以前基本是设置为nil的,现在派上用场了.因为self.imageView上可能添加了很多动画,forKey就是为了区别哪一个
     self.imageView.layer.addAnimation(flyRight, forKey: "position")
     // 添加到需要终止的地方,就可以随时终止动画了
     self.imageView.layer.removeAnimationForKey("position")
     // 移除dogImageView上所有动画
     self.imageView.layer.removeAllAnimations()
示例二 CAAnimationGroup动画组

类似View Animations中的动画组,只不过这个动画组中的动画是同时执行的

 CAAnimationGroup *aniGroup = [[CAAnimationGroup alloc]init];
    // 延迟1秒
    aniGroup.beginTime = CACurrentMediaTime() + 1;
    //整个动画时间
    aniGroup.duration = 1.0;
    aniGroup.removedOnCompletion = NO;
    aniGroup.fillMode = kCAFillModeBoth;
    // 缓慢加速缓慢减
    aniGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    //重复次数
    aniGroup.repeatCount = 2;
     // 来回往返执行   设置是否原路返回默认为不
    aniGroup.autoreverses = YES;
    //速度
    aniGroup.speed = 2.0;
    
    CABasicAnimation *scaleAni = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    scaleAni.fromValue = @(1.0);
    scaleAni.toValue = @(1.5);
    
    CABasicAnimation *rotateAni = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    rotateAni.fromValue = @(0.0);
    rotateAni.toValue = @(M_PI_4);
    
    CABasicAnimation *fadeAni = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeAni.fromValue = @(1.0);
    fadeAni.toValue = @(0.5);

    aniGroup.animations = @[scaleAni, rotateAni, fadeAni];
    [self.imageView.layer addAnimation:aniGroup forKey:nil];

示例三 CASpringAnimation弹簧效果

类似View Animations中的弹簧动画,代码实现:

  CASpringAnimation *scaleDown = [CASpringAnimation animationWithKeyPath:@"transform.scale"];
    scaleDown.fromValue = @(1.0);
    scaleDown.toValue = @(1.5);
    
    // settlingDuration:结算时间(根据动画参数估算弹簧开始运动到停止的时间,动画设置的时间最好根据此时间来设置)
    scaleDown.duration = scaleDown.settlingDuration;
    // mass:质量(影响弹簧的惯性,质量越大,弹簧惯性越大,运动的幅度越大) 默认值为1
    scaleDown.mass = 4.0;
    // stiffness:弹性系数(弹性系数越大,弹簧的运动越快)默认值为100
    scaleDown.stiffness = 1500.0;
    // damping:阻尼系数(阻尼系数越大,弹簧的停止越快)默认值为10
    scaleDown.damping = 50;
    // initialVelocity:初始速率(弹簧动画的初始速度大小,弹簧运动的初始方向与初始速率的正负一致,若初始速率为0,表示忽略该属性)默认值为0
    scaleDown.initialVelocity = 100;
    
    [self.imageView.layer addAnimation:scaleDown forKey:nil];

  • CASpringAnimation的重要属性:
  • mass:质量(影响弹簧的惯性,质量越大,弹簧惯性越大,运动的幅度越大)
  • stiffness:弹性系数(弹性系数越大,弹簧的运动越快)
  • damping:阻尼系数(阻尼系数越大,弹簧的停止越快)
  • initialVelocity:初始速率(弹簧动画的初始速度大小,弹簧运动的初始方向与初始速率的正负一致,若初始速率为0,表示忽略该属性)
  • settlingDuration:结算时间(根据动画参数估算弹簧开始运动到停止的时间,动画设置的时间最好根据此时间来设置)
示例四 CATransition专场动画
   CATransition *transition = [[CATransition alloc]init];
    transition.type = @"rippleEffect";
    transition.subtype = kCATransitionFromRight;
    transition.duration = 1.0;
    //切换图片
    [UIView transitionWithView:self.imageView duration:1.0 options:UIViewAnimationOptionTransitionFlipFromRight animations:^{
        self.imageView.image = [UIImage imageNamed:@"2"];
    } completion:nil];
    [self.imageView.layer addAnimation:transition forKey:nil];

转场动画过渡效果:


另外对于支持方向设置的动画类型还包含子类型:

    kCATransitionFromRight  从右侧转场
     kCATransitionFromLeft  从左侧转场
     kCATransitionFromTop   从顶部转场
     kCATransitionFromBottom    从底部转场
示例五 CAKeyframeAnimation

开发中情况多种多样,从一个值到另一个值的fromValuetoValue属性并不能高效的满足开发需要,比如我们要将一个view一次经过三个点呢?难道分为两次去做,那太麻烦了,CAKeyframeAnimation有个属性values是个数组完美替代了fromValue,toValue,我们可以把三个点放进values数组,解决问题

    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"position"];
    anim.duration = 2.0;
    anim.repeatCount = MAXFLOAT;
    anim.values = @[
                    [NSValue valueWithCGPoint:CGPointMake(100, 100)],
                    [NSValue valueWithCGPoint:CGPointMake(200, 300)],
                    [NSValue valueWithCGPoint:CGPointMake(50, 30)],
                    [NSValue valueWithCGPoint:CGPointMake(300, 100)]
                    ];
    anim.keyTimes = @[@(0.0), @(0.33), @(0.66), @(1.0)];
    [self.imageView.layer addAnimation:anim forKey:nil];

效果二:

    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation"];
    anim.duration = 2.0;
    anim.repeatCount = MAXFLOAT;
    anim.values = @[@(0.0), @(-M_PI_4/4), @(0.0), @(M_PI_4/4), @(0.0)];
    anim.keyTimes = @[@(0.0), @(0.25), @(0.5), @(0.75), @(1.0)];
    [self.imageView.layer addAnimation:anim forKey:nil];


动画中animationWithKeyPath:??取值如下:

    transform.scale = 比例轉換
     transform.scale.x = 闊的比例轉換
     transform.scale.y = 高的比例轉換
     transform.rotation.z = 平面圖的旋轉
     translation: 平移,值是NSSize或CGSize  translation.x, translation.y, translation.z
     opacity = 透明度
     margin
     zPosition
     backgroundColor    背景颜色
     cornerRadius    圆角
     borderWidth
     bounds
     contents
     contentsRect
     cornerRadius
     frame
     hidden
     mask
     masksToBounds
     opacity
     position
     shadowColor
     shadowOffset
     shadowOpacity
     shadowRadius

三 CAShapeLayer动画

在这我们就不讲CALayerUIBezierPath使用,大家可以自己百度学习,很简单

示例一
//贝塞尔曲线
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(100, 400)];
//    [path addQuadCurveToPoint:CGPointMake(300, 400) controlPoint:CGPointMake(150, 300)];
    [path addCurveToPoint:CGPointMake(300, 400) controlPoint1:CGPointMake(150, 300) controlPoint2:CGPointMake(200, 450)];
//创建CAShapeLayer对象
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.path = path.CGPath;
    layer.strokeColor = [UIColor purpleColor].CGColor;
    layer.fillColor = [UIColor clearColor].CGColor;
    [self.view.layer addSublayer:layer];
    
    //添加动画 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation.fromValue = @(0);
    animation.toValue = @(1);
    animation.duration = 2.0;
    [layer addAnimation:animation forKey:nil];

动画效果:


效果二:

    layer.strokeStart = 0.5;
    layer.strokeEnd = 0.5;
    
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
    animation.fromValue = @(0.5);
    animation.toValue = @(0);
    animation.duration = 2;
    
    CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    animation2.fromValue = @(0.5);
    animation2.toValue = @(1);
    animation2.duration = 2;
    
    //逐渐加粗
    CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"lineWidth"];
    animation3.fromValue = @(1);
    animation3.toValue = @(10);
    animation3.duration = 2;
    
    [layer addAnimation:animation forKey:nil];
    [layer addAnimation:animation2 forKey:nil];
    [layer addAnimation:animation3 forKey:nil];

动画效果:


实例二

说明:实例二、三不是动画效果,仅仅是对CAShapeLayer使用,可简单看下
实现下面效果


很明显它可以用 CAShapeLayer + UIBezierPath 来做,思路大概是这样,先移动到左上方的位置,然后向下划线,然后往右划线,然后往上划线,还剩一个盖子,这个盖子就用一个控制点控制曲率,非常简单,代码如下

   CGSize finalSize = CGSizeMake(self.view.width, 200);
    CGFloat layerHeight = finalSize.height * 0.3;
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(0, layerHeight)];
    [path addLineToPoint:CGPointMake(0, finalSize.height)];
    [path addLineToPoint:CGPointMake(finalSize.width, finalSize.height)];
    [path addLineToPoint:CGPointMake(finalSize.width, layerHeight)];
    [path addQuadCurveToPoint:CGPointMake(0, layerHeight) controlPoint:CGPointMake(finalSize.width/2, 0)];

    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.position = CGPointMake(0, (self.view.height - 200)/2);
    layer.path = path.CGPath;
    layer.fillColor = [UIColor orangeColor].CGColor;
    [self.view.layer addSublayer:layer];

实现效果:

示例三

代码实现

#import "TestView.h"
@implementation TestView

- (void)setMaskLayer{
    
    CGFloat viewWidth = CGRectGetWidth(self.frame);
    CGFloat viewHeight = CGRectGetHeight(self.frame);
    CGFloat rightSpace = 10.;
    CGFloat topSpace = 15.;
    CGPoint point1 = CGPointMake(0, 0);
    CGPoint point2 = CGPointMake(viewWidth-rightSpace, 0);
    CGPoint point3 = CGPointMake(viewWidth-rightSpace, topSpace);
    CGPoint point4 = CGPointMake(viewWidth, topSpace);
    CGPoint point5 = CGPointMake(viewWidth-rightSpace, topSpace+10.);
    CGPoint point6 = CGPointMake(viewWidth-rightSpace, viewHeight);
    CGPoint point7 = CGPointMake(0, viewHeight);
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:point1];
    [path addLineToPoint:point2];
    [path addLineToPoint:point3];
    [path addLineToPoint:point4];
    [path addLineToPoint:point5];
    [path addLineToPoint:point6];
    [path addLineToPoint:point7];
    [path closePath];
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.path = path.CGPath;
    
    self.layer.mask = layer;
}
@end

//使用
    TestView *testView = [[TestView alloc]initWithFrame:CGRectMake(100, 100, 150, 200)];
    testView.backgroundColor  = [UIColor cyanColor];
    [testView setMaskLayer];
    [self.view addSubview:testView];

四 CAReplicatorLayer动画

CAReplicatorLayer是一个容器层-你添加内容到其中让复制图层复制其中内容。如果你把一个单一的形状-在复制层将显示在屏幕上几种形状。
很酷的是你可以预先设定复制多少几何图形并且设定副本之间的距离,透明度或颜色都可以发生变化。因此您可以创建很酷的动画效果。

示例一
//创建图层
    CAReplicatorLayer *replicator = [CAReplicatorLayer layer];
    replicator.position = self.view.center;
    replicator.bounds = CGRectMake(0, 0, 250, 250);
    replicator.backgroundColor = [UIColor lightGrayColor].CGColor;
    [self.view.layer addSublayer:replicator];
    //创建一个振动层
    CALayer *vibrateLayer = [CALayer layer];
    CGFloat width = 25;
    CGFloat height = 100;
    vibrateLayer.bounds = CGRectMake(0, 0, width, height);
    vibrateLayer.anchorPoint = CGPointMake(0.5, 1);
    vibrateLayer.position = CGPointMake(width * 0.5, replicator.bounds.size.height);
    vibrateLayer.cornerRadius = 10;
    vibrateLayer.backgroundColor = [UIColor magentaColor].CGColor;
    [replicator addSublayer:vibrateLayer];
    
    //创建帧动画
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale.y"];
    anim.duration = 0.5;
    anim.values = @[@(1),@(0.5),@(0)];
    //旋转后再旋转到原来的位置,反极性开始
    anim.autoreverses = YES;
    anim.repeatCount = MAXFLOAT;
    [vibrateLayer addAnimation:anim forKey:nil];
    //设置复制层需要复制的个数
    replicator.instanceCount = 4;
    //设置复制出来子层的位移
    replicator.instanceTransform = CATransform3DMakeTranslation(50, 0, 0);
    // 执行动画的延迟
    replicator.instanceDelay = 0.2;
    //改变颜色
    replicator.instanceAlphaOffset = - 0.1;
    replicator.instanceRedOffset = -0.2;

效果:


其中用到的属性说明:

    //拷贝的次数
     @property NSInteger instanceCount;
     //是否开启景深效果
     @property BOOL preservesDepth;
     //当CAReplicatorLayer的子Layer层进行动画的时候,拷贝的副本执行动画的延时
     @property CFTimeInterval instanceDelay;
     //拷贝副本的3D变换
     @property CATransform3D instanceTransform;
     //拷贝副本的颜色变换
     @property(nullable) CGColorRef instanceColor;
     //每个拷贝副本的颜色偏移参数
     @property float instanceRedOffset;
     @property float instanceGreenOffset;
     @property float instanceBlueOffset;
     //每个拷贝副本的透明度偏移参数
     @property float instanceAlphaOffset;
实例二 加载动画
    int height = 40;
    int width = 40;
    
    CAReplicatorLayer *replicatorLayerMAIN  = [CAReplicatorLayer layer];
    replicatorLayerMAIN.bounds = self.view.bounds;
    replicatorLayerMAIN.position = CGPointMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0);
    [self.view.layer addSublayer:replicatorLayerMAIN];
    
    replicatorLayerMAIN.masksToBounds = YES;
    replicatorLayerMAIN.instanceCount = 15;
    replicatorLayerMAIN.instanceDelay = 1/15.0;
    CGFloat angle = (2.0 * M_PI) / (15.0);
    replicatorLayerMAIN.instanceTransform = CATransform3DMakeRotation(angle, 0, 0, 1);
    
    CALayer *replicatorLayer = [CALayer layer];
    replicatorLayer.bounds = CGRectMake(0, 0, width, height);
    replicatorLayer.backgroundColor = [UIColor whiteColor].CGColor;
    replicatorLayer.cornerRadius = width/2.0;
    replicatorLayer.position = CGPointMake(self.view.frame.size.width/2.0, self.view.frame.size.height/2.0 - 100);
    [replicatorLayerMAIN addSublayer:replicatorLayer];
    
    CABasicAnimation  *moveRectangle = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    moveRectangle.fromValue =  @1;
    moveRectangle.toValue =  @0.1;
    //否则刚开始出现的所有点一样大,所以时间减1
    moveRectangle.beginTime = CACurrentMediaTime() - 1;
    moveRectangle.duration = 1;
    moveRectangle.repeatCount = HUGE;
    [replicatorLayer addAnimation:moveRectangle forKey:@"ss"];

运行效果


五 CAEmitterLayer动画

CAEmitterLayer是ios5中苹果引入了一个新的CALayer子类。CAEmitterLayer是一个高性能的粒子引擎,可以用来做一些绚丽的粒子系统,比如爆炸,雪花火焰等等。
在UIKit中,粒子系统由两部分组成:

  • 一个或多个CAEmitterCells:发射器电池可以看作是单个粒子的原型(例如,一个单一的粉扑在一团烟雾)。当散发出一个粒子,UIKit根据这个发射粒子和定义的基础上创建一个随机粒子。此原型包括一些属性来控制粒子的图片,颜色,方向,运动,缩放比例和生命周期。
  • 一个或多个CAEmitterLayers,但通常只有一个:这个发射的层主要控制粒子的形状(例如,一个点,矩形或圆形)和发射的位置(例如,在矩形内,或边缘)。这个层具有全局的乘法器,可以施加到系统内的CAEmitterCells。这些给你一个简单的方法覆盖的所有粒子的变化。比如一个人为的例子将改变x雨来模拟风的速度。
    CAEmitterLayer提供了一个基于Core Animation的粒子发射系统,粒子用CAEmitterCell来初始化。粒子画在背景层盒边界上,CAEmitterLayers其属性说明:
birthRate:粒子产生系数,默认1.0;
emitterCells: 装着CAEmitterCell对象的数组,被用于把粒子投放到layer上;
emitterDepth:决定粒子形状的深度联系:emitter shape
emitterMode:发射模式
             NSString * const kCAEmitterLayerPoints;
             NSString * const kCAEmitterLayerOutline;
             NSString * const kCAEmitterLayerSurface;
             NSString * const kCAEmitterLayerVolume;
emitterPosition:发射位置
emitterShape:发射源的形状:
             NSString * const kCAEmitterLayerPoint;
             NSString * const kCAEmitterLayerLine;
             NSString * const kCAEmitterLayerRectangle;
             NSString * const kCAEmitterLayerCuboid;
             NSString * const kCAEmitterLayerCircle;
             NSString * const kCAEmitterLayerSphere;
emitterSize:发射源的尺寸大;
emitterZposition:发射源的z坐标位置;
lifetime:粒子生命周期
preservesDepth:不是多很清楚(粒子是平展在层上)
renderMode:渲染模式:
             NSString * const kCAEmitterLayerUnordered;
             NSString * const kCAEmitterLayerOldestFirst;
             NSString * const kCAEmitterLayerOldestLast;
             NSString * const kCAEmitterLayerBackToFront;
             NSString * const kCAEmitterLayerAdditive;
scale:粒子的缩放比例:
seed:用于初始化随机数产生的种子
spin:自旋转速度
velocity:粒子速度

CAEmitterCell属性说明:

 alphaRange:  一个粒子的颜色alpha能改变的范围;
alphaSpeed:粒子透明度在生命周期内的改变速度;
birthrate:粒子参数的速度乘数因子;
blueRange:一个粒子的颜色blue 能改变的范围
blueSpeed: 粒子blue在生命周期内的改变速度;
color: 粒子的颜色
contents:是个CGImageRef的对象,既粒子要展现的图片;
contentsRect:应该画在contents里的子rectangle:
emissionLatitude:发射的z轴方向的角度
emissionLongitude:x-y平面的发射方向
emissionRange;周围发射角度
emitterCells:粒子发射的粒子
enabled:粒子是否被渲染
greenrange: 一个粒子的颜色green 能改变的范围;
greenSpeed: 粒子green在生命周期内的改变速度;
lifetime:生命周期
lifetimeRange:生命周期范围
magnificationFilter:不是很清楚好像增加自己的大小
minificatonFilter:减小自己的大小
minificationFilterBias:减小大小的因子
name:粒子的名字
redRange:一个粒子的颜色red 能改变的范围;
redSpeed: 粒子red在生命周期内的改变速度;
scale:缩放比例:
scaleRange:缩放比例范围;
scaleSpeed:缩放比例速度:
spin:子旋转角度
spinrange:子旋转角度范围
style:不是很清楚:
velocity:速度
velocityRange:速度范围
xAcceleration:粒子x方向的加速度分量
yAcceleration:粒子y方向的加速度分量
zAcceleration:粒子z方向的加速度分量
示例一 雪花下效果
CAEmitterLayer *snowEmitter = [CAEmitterLayer layer];
    //例子发射位置
    snowEmitter.emitterPosition = CGPointMake(120,-20);
    //发射源的尺寸大小
    snowEmitter.emitterSize = CGSizeMake(self.view.bounds.size.width * 20, 20);
    //发射模式
    snowEmitter.emitterMode = kCAEmitterLayerVolume;
    //发射源的形状
    snowEmitter.emitterShape = kCAEmitterLayerLine;
    
    snowEmitter.shadowOpacity = 1.0;
    snowEmitter.shadowRadius = 0.0;
    snowEmitter.shadowOffset = CGSizeMake(0.0, 1.0);
    //粒子边缘的颜色
    snowEmitter.shadowColor = [[UIColor redColor] CGColor];
    [self.view.layer insertSublayer:snowEmitter atIndex:0];

    
    
    //创建雪花类型的粒子
    CAEmitterCell *snowflake = [CAEmitterCell emitterCell];
    //粒子的名字
    snowflake.name = @"snow";
    //粒子参数的速度乘数因子
    snowflake.birthRate = 5.0;
    snowflake.lifetime = 120.0;
    //粒子速度
    snowflake.velocity = 10.0;
    //粒子的速度范围
    snowflake.velocityRange = 10;
    //粒子y方向的加速度分量
    snowflake.yAcceleration = 2;
    //周围发射角度
    snowflake.emissionRange = 0.5 * M_PI;
    //子旋转角度范围
    snowflake.spinRange = 0.25 * M_PI;
    snowflake.contents = (id)[[UIImage imageNamed:@"3"] CGImage];
    //设置雪花形状的粒子的颜色
    snowflake.color = [[UIColor colorWithRed:0.200 green:0.258 blue:0.543 alpha:1.000] CGColor];
    
    //创建星星形状的粒子
    CAEmitterCell *snowflake1 = [CAEmitterCell emitterCell];
    //粒子的名字
    snowflake1.name = @"snow";
    //粒子参数的速度乘数因子
    snowflake1.birthRate = 5.0;
    snowflake1.lifetime = 120.0;
    //粒子速度
    snowflake1.velocity =10.0;
    //粒子的速度范围
    snowflake1.velocityRange = 10;
    //粒子y方向的加速度分量
    snowflake1.yAcceleration = 2;
    //周围发射角度
    snowflake1.emissionRange = 0.5 * M_PI;
    //子旋转角度范围
    snowflake1.spinRange = 0.25 * M_PI;
    //粒子的内容和内容的颜色
    snowflake1.contents = (id)[[UIImage imageNamed:@"4"] CGImage];
    snowflake1.color = [[UIColor colorWithRed:0.600 green:0.658 blue:0.743 alpha:1.000] CGColor];
    
    
    snowEmitter.emitterCells = [NSArray arrayWithObjects:snowflake,snowflake1,nil];

实例二 爆炸效果
 // 雪花//////////////////////////////////////////
    // Configure the particle emitter to the top edge of the screen
    CAEmitterLayer *snowEmitter = [CAEmitterLayer layer];
    snowEmitter.emitterPosition = CGPointMake(self.view.bounds.size.width / 2.0, -30);      //粒子发射器的位置
    snowEmitter.emitterSize = CGSizeMake(self.view.bounds.size.width * 2.0, 0.0);;
    snowEmitter.emitterMode = kCAEmitterLayerOutline;
    snowEmitter.emitterShape = kCAEmitterLayerRectangle;
    snowEmitter.shadowOpacity = 1.0;
    snowEmitter.shadowRadius  = 0.0;
    snowEmitter.shadowOffset  = CGSizeMake(0.0, 1.0);
    snowEmitter.shadowColor   = [[UIColor whiteColor] CGColor];
    [self.view.layer addSublayer:snowEmitter];
   
    
    CAEmitterCell *snowflake = [CAEmitterCell emitterCell];
    //    随机颗粒的大小
    snowflake.scale = 0.2;
    snowflake.scaleRange = 0.5;
    //    缩放比列速度
    //        snowflake.scaleSpeed = 0.1;
    //    粒子参数的速度乘数因子;
    snowflake.birthRate = 20.0;     //每秒产生的 cell数量
    //生命周期
    snowflake.lifetime = 60.0;     //在屏幕上的生存周期
    //    粒子速度
    snowflake.velocity = 20; // falling down slowly
    snowflake.velocityRange = 10;
    //    粒子y方向的加速度分量
    snowflake.yAcceleration = 2;
    //    周围发射角度
    snowflake.emissionRange = 0.5 * M_PI;// some variation in angle
    
    //    自动旋转
    snowflake.spinRange = 0.25 * M_PI; // slow spin
    snowflake.contents = (id) [[UIImage imageNamed:@"3"] CGImage];
    snowflake.color = [[UIColor colorWithRed:0.600 green:0.658 blue:0.743 alpha:1.000] CGColor];

    snowEmitter.emitterCells = [NSArray arrayWithObject:snowflake];
    
    
    
    
    //    [self.view.layer insertSublayer:snowEmitter atIndex:0];
    
    //// 雪花//////////////////////////////////////////
    //// 雪花//////////////////////////////////////////
    
    // Cells spawn in the bottom, moving up
    CAEmitterLayer *fireworksEmitter = [CAEmitterLayer layer];
    CGRect viewBounds = self.view.layer.bounds;
    fireworksEmitter.emitterPosition = CGPointMake(viewBounds.size.width/2.0, viewBounds.size.height);
    fireworksEmitter.emitterSize = CGSizeMake(viewBounds.size.width/2.0, 0.0);
    fireworksEmitter.emitterMode = kCAEmitterLayerOutline;
    fireworksEmitter.emitterShape = kCAEmitterLayerLine;
    fireworksEmitter.renderMode = kCAEmitterLayerAdditive;
    fireworksEmitter.seed = (arc4random()%100)+1;
    
    // Create the rocket
    CAEmitterCell* rocket = [CAEmitterCell emitterCell];
    rocket.birthRate = 5.0;              //每秒产生的 cell数量
    rocket.emissionRange = 0.25 * M_PI;  // some variation in angle
    rocket.velocity = 380;
    rocket.velocityRange = 380;
    rocket.yAcceleration = 75;
    rocket.lifetime = 1.02;// we cannot set the birthrate < 1.0 for the burst      //屏幕上的生命周期
    rocket.contents = (id) [[UIImage imageNamed:@"4"] CGImage];
//    rocket.contents         = (id) [[UIImage imageNamed:[NSString stringWithFormat:@"%u",(arc4random()%8)+1]]CGImage];
    rocket.scale = 0.3;
    //    rocket.color = [[UIColor colorWithRed:1 green:0 blue:0 alpha:1] CGColor];
    
    rocket.greenRange = 1.0;// different colors
    rocket.redRange = 1.0;
    rocket.blueRange = 1.0;
    rocket.spinRange = M_PI; // slow spin
    
    
    // the burst object cannot be seen, but will spawn the sparks
    
    // we change the color here, since the sparks inherit its value
    
    CAEmitterCell* burst = [CAEmitterCell emitterCell];
    burst.birthRate = 1.0;// at the end of travel //每秒产生的 cell数量
    burst.velocity = 0;
    burst.scale = 2.5;
    burst.redSpeed =-1.5; // shifting
    burst.blueSpeed =+1.5; // shifting
    burst.greenSpeed =+1.0; // shifting
    burst.lifetime = 0.35;     //屏幕上的生命周期
    
    
    // and finally, the sparks
    CAEmitterCell* spark = [CAEmitterCell emitterCell];
    spark.birthRate = 400;              //每秒产生的 cell数量
    spark.velocity = 125;
    spark.emissionRange = 2* M_PI; // 360 deg
    spark.yAcceleration = 75; // gravity
    spark.lifetime = 3;        //屏幕上的生命周期
    spark.contents = (id) [[UIImage imageNamed:@"5"] CGImage];
    //spark.contents          = (id) [[UIImage imageNamed:[NSString stringWithFormat:@"%u",(arc4random()%8)+1]]CGImage];
    spark.scale         =0.4;
    spark.scaleSpeed =-0.2;
    spark.greenSpeed =-0.1;
    spark.redSpeed = 0.6;
    spark.blueSpeed =-0.1;
    spark.alphaSpeed =-0.5;
    spark.spin = 2* M_PI;
    spark.spinRange = 2* M_PI;
    // putting it together
    
    fireworksEmitter.emitterCells = [NSArray arrayWithObject:rocket];
    rocket.emitterCells = [NSArray arrayWithObject:burst];
    burst.emitterCells = [NSArray arrayWithObject:spark];
    
    [self.view.layer addSublayer:fireworksEmitter];

效果:

六 参考链接

iOS粒子系统CAEmitterLayer
CAEmitterLayer和CAEmitterCell
放肆的使用UIBezierPath和CAShapeLayer画各种图形

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

推荐阅读更多精彩内容