文档章节

iOS动画篇_CALayer这些牛逼的子类你造吗

壹峰
 壹峰
发布于 2017/07/17 10:21
字数 3470
阅读 17
收藏 0

http://www.jianshu.com/p/98ff8012362a

之前说到贝塞尔曲线,今天说CALayer,哈哈哈,承上启下,放一个表情与上一篇相呼应。

CALayer

首先,CALayer其实自身有很多情况下自带隐式动画,但是需要注意的是UIView的根Layer是没有隐式动画的。下面看一下CALayer的几个重要的属性:

CALayer属性


对于大多数开发者老说,CALayer是很熟悉的一个名词,但是对于它的属性可能一知半解,上表大致说明了CALayer的几个重要属性的作用以及是否支持隐式动画,下面着重介绍几个点:

(1)frame属性

frame不支持隐式动画,所以通常使用bounds和position来设置layer的位置和大小

(2)contents

设置layer的contents可以为layer添加显示内容,最直接的便是将UIImage转化为CGImageRef赋值,其与backgroundColor的关系就相当于UIImageView的image和backgorundColor的关系。

(3)锚点 anchorPoint

锚点的取值范围为(0~1,0~1),标示此点相对于宽高的比例,默认点(0.5,0.5),锚点的位置对图层的位置以及某些动画的重心起到决定性的作用,通过锚点计算图层位置-->中心点相对于父父层的位置永远不变,锚点于中心点重合。以旋转动画为例,锚点是旋转的中心。

(4)mask

mask的作用就相当于PS中的蒙版,在一些图层处理上具有很大的优势(注:蒙版透明色为过滤掉指定layer的区域内容,不透明色为显示制定图层的区域内容)

CALayer的子类

CALayer子类图解


CALayer的子类有很多,下面说几个比较常用的:

CAShapeLayer

看一下CAShapeLayer相对于CALayer多出来的属性:

path

CAShapeLayer的path属性是他如此牛逼的一个重要起点,也是它和贝塞尔曲线紧密连接一个入口,他决定了我们要在图层上画一个什么形状。(注:当与贝塞尔曲线一起使用的时候,生成的曲线的位置是相对于生成的layer的,所以当你利用贝塞尔曲线设置了path后,再设置layer的position和bounds你会感觉很奇怪,最简单的方式就是单纯利用贝塞尔曲线决定图层的位置和大小)

CAShapeLayer *shapeLayer = [CAShapeLayer layer];
//shapeLayer.position = CGPointMake(100, 100);
//shapeLayer.bounds = CGRectMake(0, 0, 100, 100); 
//shapeLayer.anchorPoint = CGPointMake(0, 0);
shapeLayer.path = bezierPath.CGPath;
shapeLayer.fillColor = [UIColor clearColor].CGColor;
shapeLayer.strokeColor = [UIColor blueColor].CGColor;
shapeLayer.lineWidth = 10;
self.view.layer.mask = shapeLayer;
//[self.view.layer addSublayer:shapeLayer];

fillColor 和 fillRule

fillColor即layer的path的填充颜色,fillRule属性用于指定使用哪一种算法去判断画布上的某区域是否属于该图形“内部” (内部区域将被填充)。对一个简单的无交叉的路径,哪块区域是“内部” 是很直观清除的。但是,对一个复杂的路径,比如自相交或者一个子路径包围另一个子路径,“内部”的理解就不那么明了。


fillRule提供两种选项用于指定如何判断图形的内部”kCAFillRuleNonZero,kCAFillRuleEvenOdd

-(void)checkFillRule{
    UIBezierPath *path = [[UIBezierPath alloc] init];
    CGPoint circleCenter = self.view.center;
    [path moveToPoint:CGPointMake(circleCenter.x + 50, circleCenter.y)];
    [path addArcWithCenter:circleCenter radius:50 startAngle:0 endAngle:2*M_PI clockwise:YES];
    [path moveToPoint:CGPointMake(circleCenter.x + 100, circleCenter.y)];
    [path addArcWithCenter:circleCenter radius:100 startAngle:0 endAngle:2*M_PI clockwise:YES];
    [path moveToPoint:CGPointMake(circleCenter.x + 150, circleCenter.y)];
    [path addArcWithCenter:circleCenter radius:150 startAngle:0 endAngle:2*M_PI clockwise:YES];

    //create shape layer
    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.strokeColor = [UIColor redColor].CGColor;
    shapeLayer.fillColor = [UIColor greenColor].CGColor;
    shapeLayer.fillRule = kCAFillRuleNonZero;
    //shapeLayer.fillRule = kCAFillRuleEvenOdd;

    shapeLayer.lineWidth = 5;
    shapeLayer.lineJoin = kCALineJoinBevel;
    shapeLayer.lineCap = kCALineCapRound;
    shapeLayer.path = path.CGPath;

    //add it to our view
    [self.view.layer addSublayer:shapeLayer];
}

当fillRule为kCAFillRuleNonZero时:

kCAFillRuleNonZero


当fillRule为kCAFillRuleEvenOdd时:


通过上面的代码再加上下面抄袭的描述,应该能够相当清晰的理解这其中的意义。

kCAFillRuleNonZero
字面意思是“非零”。按该规则,要判断一个点是否在图形内,从该点作任意方向的一条射线,然后检测射线与图形路径的交点情况。从0开始计数,路径从左向右穿过射线则计数加1,从右向左穿过射线则计数减1。得出计数结果后,如果结果是0,则认为点在图形外部,否则认为在内部。下图演示了kCAFillRuleNonZero规则 :


kCAFillRuleEvenOdd
字面意思是“奇偶”。按该规则,要判断一个点是否在图形内,从该点作任意方向的一条射线,然后检测射线与图形路径的交点的数量。如果结果是奇数则认为点在内部,是偶数则认为点在外部。下图演示了kCAFillRuleEvenOdd 规则:

strokeColor

线颜色

strokeStart strokeEnd

两者的取值都是0~1,决定贝塞尔曲线的划线百分比,对应值的改变支持隐式动画。

UIBezierPath* bezierPath_rect = [UIBezierPath bezierPathWithRect:CGRectMake(30, 50, 100, 100)];
    bezierPath_rect.lineWidth = 10;
CAShapeLayer* shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = bezierPath_rect.CGPath;
    shapeLayer.fillColor = [UIColor redColor].CGColor;
    shapeLayer.strokeColor = [UIColor blackColor].CGColor;
    shapeLayer.lineWidth = 10;
    shapeLayer.strokeStart = 0;
    shapeLayer.strokeEnd = 0.3;
    [self.view.layer addSublayer:shapeLayer];

运行结果:

lineWidth

线宽

miterLimit

最大斜接长度,只有lineJoin属性为kCALineJoinMiter时miterLimit才有效,当衔接角度太小时,斜接长度就会很大,如果设置了 miterLimit并且当斜接长度大于这个值时,便会对应裁切掉多余区域:


设置miterLimit后:

lineCap

线端点类型,也就是对应曲线结束的点的显示样式。

lineJoin

连接点类型,也就是对应曲线节点的位置的显示样式。

lineDashPattern

虚线设置,为一个数组,数组中奇数位实线长度,偶数位带遍空白长度(注意:这里的奇数,偶数以数组的第一个元素索引为1计算)

lineDashPhase

虚线开始的位置,可以使用此属性做一个滚动的虚线框。

    CAShapeLayer* dashLineShapeLayer = [CAShapeLayer layer];
    //创建贝塞尔曲线
    UIBezierPath* dashLinePath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 200, 100) cornerRadius:20];

    dashLineShapeLayer.path = dashLinePath.CGPath;
    dashLineShapeLayer.position = CGPointMake(100, 100);
    dashLineShapeLayer.fillColor = [UIColor clearColor].CGColor;
    dashLineShapeLayer.strokeColor = [UIColor whiteColor].CGColor;
    dashLineShapeLayer.lineWidth = 3;
    dashLineShapeLayer.lineDashPattern = @[@(6),@(6)];
    dashLineShapeLayer.strokeStart = 0;
    dashLineShapeLayer.strokeEnd = 1;
    dashLineShapeLayer.zPosition = 999;
    //
    [self.view.layer addSublayer:dashLineShapeLayer];

    //
    NSTimeInterval delayTime = 0.3f;
    //定时器间隔时间
    NSTimeInterval timeInterval = 0.1f;
    //创建子线程队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //使用之前创建的队列来创建计时器
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    //设置延时执行时间,delayTime为要延时的秒数
    dispatch_time_t startDelayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC));
    //设置计时器
    dispatch_source_set_timer(_timer, startDelayTime, timeInterval * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(_timer, ^{
        //执行事件
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            CGFloat _add = 3;
            dashLineShapeLayer.lineDashPhase -= _add;
        });
    });
    // 启动计时器
    dispatch_resume(_timer);

效果如图:(视频好像有点快...)

其实CAShapeLayer的用处很多,能实现很多动画效果的同时,也可以实现很多蒙版效果,心有多大,功能就有多大。

之前写过一个点击扩散的库,主要用到蒙版mask以及shapeLayer和核心动画,您上眼:

//
//  UIView+YSTransform.h
//  JR_New_AnimationDemo
//
//  Created by ys on 2016/3/20.
//  Copyright © 2016年 ys. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface UIView (YSTransform)<CAAnimationDelegate>

-(void)YSTransform_circleColor_toColor:(UIColor*)toColor Duration:(CGFloat)duration StartPoint:(CGPoint)startPoint;

-(void)YSTransform_circleImage_toImage:(UIImage*)toImage Duration:(CGFloat)duration StartPoint:(CGPoint)startPoint;

-(void)YSTransForm_beginZoom_max:(CGFloat)max min:(CGFloat)min;
-(void)YSTransForm_StopZoom;
@end
//
//  UIView+YSTransform.m
//  JR_New_AnimationDemo
//
//  Created by ys on 2016/3/20.
//  Copyright © 2016年 ys. All rights reserved.
//

#import "UIView+YSTransform.h"
#import <objc/runtime.h>

@implementation UIView (YSTransform)

-(void)YSTransform_circleColor_toColor:(UIColor*)toColor Duration:(CGFloat)duration StartPoint:(CGPoint)startPoint{
    CALayer *tempLayer = objc_getAssociatedObject(self, @"tempLayer");
    if (!tempLayer) {
        tempLayer = [[CALayer alloc] init];
        tempLayer.bounds = self.bounds;
        tempLayer.position = self.center;
        tempLayer.backgroundColor = self.backgroundColor.CGColor;
        [self.layer addSublayer:tempLayer];
        objc_setAssociatedObject(self, @"tempLayer", tempLayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    //
    tempLayer.contents = nil;
    tempLayer.backgroundColor = toColor.CGColor;
    CGFloat screenHeight = self.frame.size.height;
    CGFloat screenWidth = self.frame.size.width;
    CGRect rect = CGRectMake(startPoint.x, startPoint.y, 2, 2);
    UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:rect];
    UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:startPoint radius:sqrt(screenHeight * screenHeight + screenWidth * screenWidth)  startAngle:0 endAngle:M_PI*2 clockwise:YES];

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.path = endPath.CGPath;
    tempLayer.mask = maskLayer;

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.delegate = self;

    animation.fromValue = (__bridge id)(startPath.CGPath);
    animation.toValue = (__bridge id)((endPath.CGPath));
    animation.duration = 1;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [animation setValue:@"YSCircleColor_value" forKey:@"YSCircleColor_key"];
    [maskLayer addAnimation:animation forKey:@"YSCircleColor"];
}

-(void)YSTransform_circleImage_toImage:(UIImage*)toImage Duration:(CGFloat)duration StartPoint:(CGPoint)startPoint{
    CALayer *tempLayer = objc_getAssociatedObject(self, @"tempLayer");
    if (!tempLayer) {
        tempLayer = [[CALayer alloc] init];
        tempLayer.bounds = self.bounds;
        tempLayer.position = self.center;
        tempLayer.backgroundColor = self.backgroundColor.CGColor;
        [self.layer addSublayer:tempLayer];
        objc_setAssociatedObject(self, @"tempLayer", tempLayer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    tempLayer.contents = (id)toImage.CGImage;
    //
    CGFloat screenHeight = self.frame.size.height;
    CGFloat screenWidth = self.frame.size.width;
    CGRect rect = CGRectMake(startPoint.x, startPoint.y, 2, 2);
    UIBezierPath *startPath = [UIBezierPath bezierPathWithOvalInRect:rect];
    UIBezierPath *endPath = [UIBezierPath bezierPathWithArcCenter:startPoint radius:sqrt(screenHeight * screenHeight + screenWidth * screenWidth)  startAngle:0 endAngle:M_PI*2 clockwise:YES];

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.path = endPath.CGPath;
    tempLayer.mask = maskLayer;

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
    animation.delegate = self;

    animation.fromValue = (__bridge id)(startPath.CGPath);
    animation.toValue = (__bridge id)((endPath.CGPath));
    animation.duration = 1;
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    [animation setValue:@"YSCircleImage_value" forKey:@"YSCircleImage_key"];
    [maskLayer addAnimation:animation forKey:@"YSCircleImage"];
}
//
-(void)YSTransForm_beginZoom_max:(CGFloat)max min:(CGFloat)min{
    [UIView animateWithDuration:0.3 animations:^{
        self.transform = CGAffineTransformMakeScale(max, max);
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.3 animations:^{
            self.transform = CGAffineTransformMakeScale(min, min);
        } completion:^(BOOL finished) {
            NSNumber *nextStop = objc_getAssociatedObject(self, @"nextAniStop");
            if ([nextStop boolValue]) {
                [UIView animateWithDuration:0.3 animations:^{
                    self.transform = CGAffineTransformMakeScale(1, 1);
                } completion:^(BOOL finished) {
                    self.transform = CGAffineTransformMakeScale(1, 1);
                    objc_setAssociatedObject(self, @"nextAniStop", @(0), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
                }];
            }else{
                [self YSTransForm_beginZoom_max:max min:min];
            }
        }];
    }];
}

-(void)YSTransForm_StopZoom{
    objc_setAssociatedObject(self, @"nextAniStop", @(1), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

//
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag{
    if (flag) {
        CALayer *tempLayer = objc_getAssociatedObject(self, @"tempLayer");
        if ([anim valueForKey:@"YSCircleColor_key"]) {
            self.layer.contents = nil;
            self.backgroundColor = [UIColor colorWithCGColor:tempLayer.backgroundColor];
        }else if ([anim valueForKey:@"YSCircleImage_key"]){
            self.layer.contents = tempLayer.contents;
        }
    }
}
@end

效果如下:

另外,其实我们看到的很多酷炫的变幻莫测的动画很多都是CAShapeLayer或者Quartz 2D绘图配合帧率刷新的结果。来,有时间我给你讲讲啊。

CAGradientLayer

下面再说一个比较常用的子类CAGradientLayer,我们一般使用它生成平滑的颜色过渡。大致的效果如下:


同样,我们还是从它的特有属性入手:

colors

在Layer中现实的几种颜色并完成完美过渡,和CAShapeLayerpath一样,colorsCAGradientLayer特殊属性的起点,也就是x 显示的要素。

locations

颜色区间分布比例,默认为线性均匀分布。取值范围为0~1递增,一般来说其中的元素个数应与colors中的元素个数相同,不同时系统会自行处理分布规则。
设置 gradientLayer.locations = @[@(0.3),@(0.7)];

startPoint endPoint

startPoint决定了变色范围的起始点,endPoint决定了变色范围的结束点,两者的连线决定变色的趋势:

gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(1, 1);

gradientLayer.startPoint = CGPointMake(0.5, 0);
gradientLayer.endPoint = CGPointMake(1, 1);

gradientLayer.startPoint = CGPointMake(0, 0.5);
gradientLayer.endPoint = CGPointMake(1, 1);

gradientLayer.locations = @[@(0.3),@(0.7)];
//
gradientLayer.startPoint = CGPointMake(0, 0);
gradientLayer.endPoint = CGPointMake(0.5, 0.5);


注意:locations是相对于startPointendPoint的变化范围而言的。
看到这,你一定会说,这个玩意有什么卵用。


下面找一个之前写过的一个Demo,简单的彩色进度条:

//CAGradientLayer
-(void)creatGradientLayer{
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.bounds = CGRectMake(0, 0, 220, 220);
    gradientLayer.position = self.view.center;
    [self.view.layer addSublayer:gradientLayer];
    //
    NSMutableArray *colorArray = [NSMutableArray new];
    for (NSInteger hue = 0; hue <= 360; hue += 5) {
        UIColor *color = [UIColor colorWithHue:1.0*hue/360.0
                                    saturation:1.0
                                    brightness:1.0
                                         alpha:1.0];
        [colorArray addObject:(id)color.CGColor];
    }
    //
    gradientLayer.colors = colorArray;
    //gradientLayer.locations = @[@(0.3),@(0.7)];
    //
    gradientLayer.startPoint = CGPointMake(0, 0);
    gradientLayer.endPoint = CGPointMake(1, 1);
    //ShapeLayer
    UIBezierPath *bezierP = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 200, 200)];
    CAShapeLayer* shapeLayer = [[CAShapeLayer alloc] init];
    shapeLayer.path = bezierP.CGPath;
    shapeLayer.lineWidth = 10;
    shapeLayer.fillColor = [UIColor clearColor].CGColor;
    shapeLayer.strokeColor = [UIColor blueColor].CGColor;
    shapeLayer.lineCap = kCALineCapRound;
    shapeLayer.strokeStart = 0;
    shapeLayer.strokeEnd = 0;
    gradientLayer.mask = shapeLayer;

    //
    NSTimeInterval delayTime = 1.0f;
    NSTimeInterval timeInterval = 0.5f;
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_time_t startDelayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC));
    dispatch_source_set_timer(_timer, startDelayTime, timeInterval * NSEC_PER_SEC, 0.1 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(_timer, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            if (shapeLayer.strokeEnd < 0.6) {
                shapeLayer.strokeEnd += 0.4;
            }else if (shapeLayer.strokeEnd < 0.8){
                shapeLayer.strokeEnd += 0.2;
            }else if (shapeLayer.strokeEnd < 1){
                shapeLayer.strokeEnd += 0.1;
            }else{
                dispatch_source_cancel(_timer);
            }
        });
    });
    dispatch_resume(_timer);
}

运行结果

CAEmitterLayer

CAEmitterLayer,他的属性真的是看的让人生无可恋,就算你这个字段什么意思,写出你想要的效果也需要一个大量的调整的过程,简直爆炸。之前写了一个雨夹雪,供大家参考。

#pragma mark CAEmitterLayer && CAEmitterCell
/*
 CAEmitterLayer 属性介绍

 birthRate:粒子产生系数,默认1.0;

 emitterCells: 装着CAEmitterCell对象的数组,被用于把粒子投放到layer上;

 emitterDepth:决定粒子形状的深度联系:emittershape

 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:粒子速度
 */
- (void)startCAEmitterLayer {
    // EmitterLayer

    CGRect showRect = self.view.bounds;
    UIView *view = [[UIView alloc] initWithFrame:showRect];
    view.backgroundColor = [UIColor blackColor];
    [self.view addSubview:view];

    self.emitterLayer = [CAEmitterLayer layer];
    self.emitterLayer.frame = view.bounds;
    self.emitterLayer.masksToBounds = YES;
    self.emitterLayer.emitterShape = kCAEmitterLayerLine;
    self.emitterLayer.emitterMode = kCAEmitterLayerSurface;
    self.emitterLayer.emitterSize = showRect.size;
    self.emitterLayer.emitterPosition = CGPointMake(showRect.size.width / 2.f, - 20);
    [self setEmitterCell];
    [view.layer addSublayer:self.emitterLayer];
}

/*
 CAEmitterCell 属性介绍

 CAEmitterCell类代表从CAEmitterLayer射出的粒子;emitter cell定义了粒子发射的方向。

 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:生命周期范围      lifetime= lifetime(+/-) lifetimeRange

 magnificationFilter:不是很清楚好像增加自己的大小

 minificatonFilter:减小自己的大小

 minificationFilterBias:减小大小的因子

 name:粒子的名字

 redRange:一个粒子的颜色red 能改变的范围;

 redSpeed; 粒子red在生命周期内的改变速度;

 scale:缩放比例:

 scaleRange:缩放比例范围;

 scaleSpeed:缩放比例速度:

 spin:子旋转角度

 spinrange:子旋转角度范围

 style:不是很清楚:

 velocity:速度

 velocityRange:速度范围

 xAcceleration:粒子x方向的加速度分量

 yAcceleration:粒子y方向的加速度分量

 zAcceleration:粒子z方向的加速度分量

emitterCells:粒子发射的粒子

注意:粒子同样有emitterCells属性,也就是说粒子同样可以发射粒子。
 */
- (void)setEmitterCell {
    CAEmitterCell *rainflake = [CAEmitterCell  emitterCell];
    rainflake.birthRate = 5.f;
    rainflake.speed = 10.f;
    rainflake.velocity        = 10.f;
    rainflake.velocityRange   = 10.f;
    rainflake.yAcceleration   = 1000.f;
    rainflake.contents        = (__bridge id)([UIImage imageNamed:@"rain.png"].CGImage);
    rainflake.color           = [UIColor whiteColor].CGColor;
    rainflake.lifetime        = 160.f;
    rainflake.scale           = 0.2f;
    rainflake.scaleRange      = 0.f;


    CAEmitterCell *snowflake  = [CAEmitterCell emitterCell];
    snowflake.birthRate       = 1.f;
    snowflake.speed           = 10.f;
    snowflake.velocity        = 2.f;
    snowflake.velocityRange   = 10.f;
    snowflake.yAcceleration   = 10.f;
    snowflake.emissionRange   = 0.5 * M_PI;
    snowflake.spinRange       = 0.25 * M_PI;
    snowflake.contents        = (__bridge id)([UIImage imageNamed:@"snow.png"].CGImage);
    snowflake.color           = [UIColor cyanColor].CGColor;
    snowflake.lifetime        = 160.f;
    snowflake.scale           = 0.5;
    snowflake.scaleRange      = 0.3;
    //添加到EmitterLayer中
    self.emitterLayer.emitterCells = @[snowflake,rainflake];
}

运行效果:

剩下的那些CALayer的子类,正好我有空,如果你也有空,来这里,我说,你听,CALayer这些牛逼的子类你造吗_补全篇



作者:CornBallast
链接:http://www.jianshu.com/p/98ff8012362a
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

本文转载自:

共有 人打赏支持
壹峰
粉丝 7
博文 567
码字总数 9382
作品 0
广州
其他
私信 提问
GPU vs CPU in iOS

一直以来,我们做产品的时候并没有特别的去考虑CPU/GPU的使用,最近为了提升可视化功能的性能,发现合理使用GPU也是一个可以好好研究的部分,这里总结一下一些有用的信息。 中央处理器 CPU ...

雨_树
07/10
0
0
iO6 Programming pushing the limits 阅读笔记

目录 第一部分 iOS6新内容 第二部分 从每天工具中获取更多(介绍日常使用控件和框架的潜力) 第三部分 完成任务的正确工具(介绍不是那么常用的控件和框架) 第四部分 发挥到极限(深入理解i...

云飞扬v5
2015/11/09
0
0
iOS开发系列--让你的应用“动”起来

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jianxin160/article/details/47753223 --iOS核心动画 概览 在iOS中随处都可以看到绚丽的动画效果,实现这些动...

KenshinCui
2015/08/18
0
0
GitHub 上排名前 100 的 Objective-C 项目简介

主要对当前 GitHub 排名前 100 的项目做一个简单的简介, 方便初学者快速了解到当前 Objective-C 在 GitHub 的情况. 若有任何疑问可通过微博@李锦发联系我 项目名称 项目信息 1. AFNetworkin...

oschina
2015/04/11
33.2K
28
CALayer与UIView的关系

UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理。UIView本身更像是一个CALayer的管理器,...

Megan_zhou
2014/04/30
0
0

没有更多内容

加载失败,请刷新页面

加载更多

区块链安全 - 以太坊短地址攻击

1 基础知识 EVM虚拟机在解析合约的字节码时,依赖的是ABI的定义,从而去识别各个字段位于字节码的什么地方。关于ABI,可以阅读这个文档: https://github.com/ethereum/wiki/wiki/Ethereum-C...

HiBlock
10分钟前
0
0
自定义函数及内部函数

变量的作用域 局部变量 global $Global及其他超全局数组 静态变量 仅初始化赋值 保留于内存直到response才销毁 global和static变量的区别 global:局部变量全局话 static:定义静态局部变量 函...

关元
10分钟前
0
0

中国龙-扬科
23分钟前
1
0
python包

https://www.lfd.uci.edu/~gohlke/pythonlibs/

陆朋
33分钟前
1
0
一文弄懂“分布式锁”,一直以来你的选择依据正确吗?

本文主要会关注的问题是“分布式锁”的问题。 多线程情况下对共享资源的操作需要加锁,避免数据被写乱,在分布式系统中,这个问题也是存在的,此时就需要一个分布式锁服务。 常见的分布式锁实...

Java干货分享
41分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部