美文网首页iOSiOS开发iOS 技术文档收录
iOS动画篇_CALayer这些牛逼的子类你造吗

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

作者: 穿山甲救蛇精 | 来源:发表于2017-04-24 18:14 被阅读5370次

    之前说到贝塞尔曲线,今天说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这些牛逼的子类你造吗_补全篇

    相关文章

      网友评论

      • 小時間光:给大佬递茶 顺便求demo。。
      • 蜿蜒花骨朵:就服你出牛逼的心态写代码:smirk:
      • 84df298b2705:问个问题,控件上本身有控件,-(void)YSTransform_circleColor_toColor:(UIColor*)toColor Duration:(CGFloat)duration StartPoint:(CGPoint)startPoint;用这几个方法会出现背景变了,但是之前的控件就看不到了,这个要怎么处理啊
        84df298b2705:@CornBallast 也没法贴代码。。。就是我放了一个UIButton在self.view上,点击按钮触发这个方法,按钮就会看不到,但是用Debug View Hierarchy看,层级什么的也是没问题一切OK,按钮按下时也是能看到的,不知道是哪里的问题
        穿山甲救蛇精:我的演示的动画上不是也有控件么?我可能没有太明白你的意思:sweat_smile:
      • 84df298b2705:不光写的好,扎实,全干货。。。。。。段子也是满篇飞。。只做程序猿亏了你了
      • 篁小韵:真的,有demo就更棒棒了。
      • 5ec1da87f063:有demo就更好了....
      • z我要是唐僧就留在女儿国:不评论贼难受,这个研究的贼鸡儿屌!我只用到了CAShapeLayer,膜拜大神!
        JaiUnChat:你要是唐僧你都到不了女儿国
        yep灬:@z我要是唐僧就留在女儿国 就服你这个评论,哈哈
      • 九剑仙:赞一个
      • 龙伟17:配的一手好图
      • 春泥Fu:不就是膝盖嘛,给你就是了!
      • 改个Id:学习了
      • 五锅锅:点赞
      • 你只是个Baby:零回复惨案,帮大神结案了。🤣同时想请教一下前辈,我目前有点迷茫了,不知道下一步怎么提升自己的技能了。还请前辈赐教!看完你的runtime系列,感触许多,写的很生动😁
        蛮大人_3b6c:必须支持下兄弟,写的清晰易懂 诙谐幽默
        你只是个Baby:@CornBallast 多谢
        穿山甲救蛇精:这取决你自己的职业规划 再确定自己需要的技能 本方向上多看多写多涉猎 明白原理自己封装和直接用别人封装好的东西是两种不同的体验 (我不是大神,我只是一个半夜写代码的程序员):pray:

      本文标题:iOS动画篇_CALayer这些牛逼的子类你造吗

      本文链接:https://www.haomeiwen.com/subject/sxxsottx.html