• Emitter Layers 发射极层


    发射极层(CAEmitterLayer)是在一定程度上与动画图像相提并论的:一旦你建立了一个发射极层,它会自己执行所有的动画。该动画的性质是相当窄的:一个发射极层发射的粒子,是CAEmitterCell实例。但是,通过发射极层的属性和它的发射单元的巧妙设置,可以实现一些惊人的效果。此外,使用Core Animation的动画本身就是动画。

    下面是CAEmitterCell一些有用的基本属性:

    contents, contentsRect

    这些都是仿照同名的CALayer的属性,虽然CAEmitterLayer不是CALayer的子类;对应于一个图像(CGImageRef)和一个CGRect指定这个图像的区域。他们定义了单元格将要绘制的图像。

    birthrate, lifetime

    分别表示,每秒钟发射多少个单元,每个单元存活多少时间。

    velocity

    一个单元移动的速度,文档中没有说明单位是什么,可能是每秒钟移动多少个点。

    emissionLatitude, emissionLongitude

    单元从发射层射出来的角度,相对于垂直的变化。Longitude是平面内的角度,latitude是平面上的角度。

    下面的代码构造了一个基本的发射单元:

    UIGraphicsBeginImageContextWithOptions(CGSizeMake(10,10), NO, 1);
    CGContextRef con = UIGraphicsGetCurrentContext();
    CGContextAddEllipseInRect(con, CGRectMake(0,0,10,10));
    CGContextSetFillColorWithColor(con, [UIColor grayColor].CGColor);
    CGContextFillPath(con);
    UIImage* im = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    CAEmitterCell* cell = [CAEmitterCell emitterCell];
    cell.birthRate = 5;
    cell.lifetime = 1;
    cell.velocity = 100;
    cell.contents = (id)im.CGImage;
    

    在第一行中,我们没有在双分辨率的屏幕中把scale 乘以2,因为CAEmitterLayer就像CALayer一样,没有contentsScale属性。我们将从这个image中得到一个CGImage,我们不想它的大小增加一倍。

    其结果是,灰色小圆圈缓慢而稳定地每秒钟射出5个,每一个都存活5秒钟。现在我们需要构造一个发射这些小圆圈的发射极层。下面是一些CAEmitterLayer的基本属性(是从CALayer继承之外的),这些属性定义了一个假想的发射器,会产生发射极单元:

    emitterPosition

    该发射器应该是在superlayer的坐标内。你可以选择性地为这个点添加一个三维立体位置,emitterZPosition。

    emitterSize

    发射器的大小

    emitterShape

    发射器的形状。形状的尺寸依赖于发射器的大小;长方体形状也依赖于第三个尺寸的大小,emitterDepth。你可以选择:

    • kCAEmitterLayerPoint

    • kCAEmitterLayerLine

    • kCAEmitterLayerRectangle

    • kCAEmitterLayerCuboid

    • kCAEmitterLayerCircle

    • kCAEmitterLayerSphere

    emitterMode

    在发射器形状的哪个区域发射这些单元,你可以选择:

    • kCAEmitterLayerPoints

    • kCAEmitterLayerOutline

    • kCAEmitterLayerSurface

    • kCAEmitterLayerVolume

    让我们从一个最简单的情况开始吧,就是一个点的发射器:

    CAEmitterLayer* emit = [CAEmitterLayer new];
    emit.emitterPosition = CGPointMake(30,100);
    emit.emitterShape = kCAEmitterLayerPoint;
    emit.emitterMode = kCAEmitterLayerPoints;
    

    我们要告诉发射器要发射什么类型的单元,通过设置它的emitterCells属性(一个CAEmitterCell 的数组)。然后我们把这个发射器添加到我们的界面上,最后开始发射:

    emit.emitterCells = @[cell];
    [self.view.layer addSublayer:emit];
    

    其结果是从点{30,100}发出的灰色圆圈络绎不绝,每个圆圈稳步前进到右侧,一秒钟后消失

    现在,我们已经成功地创造了一个无聊的发射极层,我们可以开始改变一些参数。emissionRange属性定义了一个锥形,单元会从这个锥形发射出来;如果我们增加birthRate和扩大emissionRange,我们得到的东西看起来像水从水管流出来:

    cell.birthRate = 100;
    cell.lifetime = 1.5;
    cell.velocity = 100;
    cell.emissionRange = M_PI/5.0;
    

    另外,当单元移动时,它可以每个维度上进心加速或者减速,利用其xAcceleration,yAcceleration和zAcceleration属性。在这里,我们把水流变成沿梯形留下,像瀑布一样从左边留下来:

    cell.xAcceleration = -40;
    cell.yAcceleration = 200;
    

    单元行为的所有方面都可以是随机的,使用下面CAEmitterCell属性:

    lifetimeRange, velocityRange

    单元存活时间和速度的随机变化范围

    scale

    scaleRange, scaleSpeed

    单元大小改变的范围,这个range 和 speed 决定了在单元存活时间里,它的大小变化的范围和速度

    color

    redRange, greenRange, blueRange, alphaRange

    redSpeed, greenSpeed, blueSpeed, alphaSpeed

    这color是根据单元内容图像的不透明度绘制的颜色,它结合了图像的颜色,因此,如果我们希望这个颜色是完全纯色,我们的内容图像应该只能用白色。range和speed决定了颜色的每个分量改变的范围和速度。

    spin, spinRange

    spin是自转的速度(弧度每秒);range决定了在单元存活时间里速度的变化范围

    在这里,我们添加一些变化,使得圆圈表现稍微彼此独立。有些存活比别的更长,一些发射的初始速度比别的更快。他们都开始于蓝色的底色,然后在流的一半时变成绿色:

    cell.lifetimeRange = .4;
    cell.velocityRange = 20;
    cell.scaleRange = .2;
    cell.scaleSpeed = .2;
    cell.color = [UIColor blueColor].CGColor;
    cell.greenRange = .5;
    cell.greenSpeed = .75;
    

    一旦发射极层显示和在执行动画,你可以通过KVC来改变单元的属性和发射极层自己的属性。你可以通过发射极层的@"emitterCells"键路径来访问发射单元,为了指定一个单元类型,可以使用它的name属性。例如,我们设置 cell.name = @"circle",现在我们改变cell 的greenSpeed,让每个单元在生命周期的早期就开始从蓝色变为绿色:

    [emit setValue:@3.0f
        forKeyPath:@"emitterCells.circle.greenSpeed"];
    

    这样做的意义是,这样的变化可以自己进行动画!在这里,我们将给发射极层添加一个重复动画让每个单元的Greenspeed在两个值间来回变化。其结果是,这个流中,随着时间的推移,单元的颜色介于蓝色和绿色之间:

    NSString* key = @"emitterCells.circle.greenSpeed";
    CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:key];
    ba.fromValue = @-1.0f;
    ba.toValue = @3.0f;
    ba.duration = 4;
    ba.autoreverses = YES;
    ba.repeatCount = HUGE_VALF;
    [emit addAnimation:ba forKey:nil];
    

    一个CAEmitterCell自身也可以作为一个发射器---就是说,它可以有自己的单元。 CAEmitter和CAEmitterCell都实现了CAMediaTiming协议,它们的beginTime 和 duration可以用来管理执行的次数,尽可能地在一个组合动画里。例如,下面的代码会导致我们现有的瀑布式流在“喷嘴”的区域(发射极)会喷射微小液滴:

    CAEmitterCell* cell2 = [CAEmitterCell emitterCell];
    cell.emitterCells = @[cell2];
    cell2.contents = (id)im.CGImage;
    cell2.emissionRange = M_PI;
    cell2.birthRate = 200;
    cell2.lifetime = 0.4;
    cell2.velocity = 200;
    cell2.scale = 0.2;
    cell2.beginTime = .04;
    cell2.duration = .2;
    

    但是,如果我们改变beginTime太大,微小液滴会发生在梯级的底部附近。这时我们还必须增加duration,或两个属性都不设置,因为如果持续时间duration小于beginTime,将没有发射发生:

    cell2.beginTime = .7;
    cell2.duration = .8;
    

    我们还可以通过改变发射器本身的行为来改变图像。这种变化会把发射器变成一条线,让我们的梯级变宽:

    emit.emitterPosition = CGPointMake(100,25);
    emit.emitterSize = CGSizeMake(100,100);
    emit.emitterShape = kCAEmitterLayerLine;
    emit.emitterMode = kCAEmitterLayerOutline;
    cell.emissionLongitude = 3*M_PI/4;
    
  • 相关阅读:
    vue拖拽排序(vueslicksort)点击失效的解决方式
    Redis 的操作为什么是的原子性的详解
    SQL Server Express 自动安装实现
    解决phpstorm项目版本设置锁不定的问题
    git报错:See the 'Note about fastforwards' in 'git push help' for details.
    vm虚拟机centos系统拷贝到另一台电脑不分配ip的问题
    在centos7下部署aspnetcore webapi项目
    cento7为root修改简单密码
    TP生产环境出现读写失败的错误的解决方案
    查看SQL Server性能时常用的性能计数器
  • 原文地址:https://www.cnblogs.com/YungMing/p/4032635.html
Copyright © 2020-2023  润新知