iOS 使用核心动画加粒子发射器实现的点赞按钮

myxuee 7年前
   <p><strong>1.使用到的类</strong></p>    <pre>  <code class="language-objectivec">CAKeyframeAnimation       // 核心动画-关键帧动画  CAEmitterLayer            // 粒子发射器(其实就是一个Layer,其父类是CALayer)  CAEmitterCell             // 粒子  PS:核心动画应该不用多说了;  CAEmitterLayer和CAEmitterCell,其实可以比喻成“炮”和“炮弹”,应该不难理解;</code></pre>    <p><strong>2.直接上部分关键代码 代码中会有详细的注释</strong></p>    <p>2.1 .m中需要拥有的属性</p>    <pre>  <code class="language-objectivec">/** weak类型 粒子发射器 */  @property (nonatomic, weak)  CAEmitterLayer *emitterLayer;</code></pre>    <p>2.2 initWithFrame: 方法中</p>    <pre>  <code class="language-objectivec">- (instancetype)initWithFrame:(CGRect)frame {      self = [super initWithFrame:frame];      if (self) {          // 配置粒子发射器方法          [self setupEmitter];      }      return self;  }</code></pre>    <p>2.3 setSelected: 方法中</p>    <pre>  <code class="language-objectivec">- (void)setSelected:(BOOL)selected {      [super setSelected:selected];      // 开始关键帧动画      [self keyframeAnimation];  }</code></pre>    <p>2.4 layoutSubviews 方法中</p>    <pre>  <code class="language-objectivec">- (void)layoutSubviews{      [super layoutSubviews];      /// 设置粒子发射器的锚点      _emitterLayer.position = self.imageView.center;    }</code></pre>    <p>2.5 setupEmitter 方法中( 配置粒子发射器方法 )</p>    <pre>  <code class="language-objectivec">- (void)setup {      // 粒子使用CAEmitterCell初始化      CAEmitterCell *emitterCell   = [CAEmitterCell emitterCell];      // 粒子的名字,在设置喷射个数的时候会用到      emitterCell.name             = @"emitterCell";      // 粒子的生命周期和生命周期范围      emitterCell.lifetime         = 0.7;      emitterCell.lifetimeRange    = 0.3;      // 粒子的发射速度和速度的范围      emitterCell.velocity         = 30.00;      emitterCell.velocityRange    = 4.00;      // 粒子的缩放比例和缩放比例的范围      emitterCell.scale            = 0.1;      emitterCell.scaleRange       = 0.02;        // 粒子透明度改变范围      emitterCell.alphaRange       = 0.10;      // 粒子透明度在生命周期中改变的速度      emitterCell.alphaSpeed       = -1.0;      // 设置粒子的图片      emitterCell.contents         = (id)[UIImage imageNamed:@"Sparkle3"].CGImage;        /// 初始化粒子发射器      CAEmitterLayer *layer        = [CAEmitterLayer layer];      // 粒子发射器的 名称      layer.name                   = @"emitterLayer";      // 粒子发射器的 形状(可以想象成打仗时,你需要的使用的炮的形状)      layer.emitterShape           = kCAEmitterLayerCircle;      // 粒子发射器 发射的模式      layer.emitterMode            = kCAEmitterLayerOutline;      // 粒子发射器 中的粒子 (炮要使用的炮弹)      layer.emitterCells           = @[emitterCell];      // 定义粒子细胞是如何被呈现到layer中的      layer.renderMode             = kCAEmitterLayerOldestFirst;      // 不要修剪layer的边界      layer.masksToBounds          = NO;      // z 轴的相对坐标 设置为-1 可以让粒子发射器layer在self.layer下面      layer.zPosition              = -1;      // 添加layer      [self.layer addSublayer:layer];      _emitterLayer = layer;  }</code></pre>    <p>ps:这里有一点需要详细解释一下, CAEmitterCell 的属性一般有两个参数:一个平均值和一个“Range”,比如:</p>    <pre>  <code class="language-objectivec">// 粒子的生命周期和生命周期范围    emitterCell.lifetime         = 0.7;    emitterCell.lifetimeRange    = 0.3;</code></pre>    <p>这里苹果的官方文档是这样解释的:</p>    <pre>  <code class="language-objectivec">每一个Layer都有它自己的随机数发生器,粒子的属性大部分都被定义为一个平均值和一个范围值,  如粒子的速度,这个属性的值分布的区间为:[ M - R / 2,M + R / 2 ]。    然后 这个公式里面  M:均值(拿上面代码说就是 emitterCell.lifetime)  R:范围值(mitterCell.lifetimeRange)    然后我们就可根据公式算出上面我设置的粒子的生命周期的范围是[0.7-0.3/2 , 0.7+0.3/2]</code></pre>    <p>2.6 keyframeAnimation 方法中 (开始关键帧动画)</p>    <pre>  <code class="language-objectivec">- (void)animation {       // 创建关键帧动画       CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];      if (self.selected) {          animation.values = @[@1.5 ,@0.8, @1.0,@1.2,@1.0];          animation.duration = 0.5;          // 粒子发射器 发射          [self startFire];      }else      {          animation.values = @[@0.8, @1.0];          animation.duration = 0.4;      }      // 动画模式      animation.calculationMode = kCAAnimationCubic;      [self.imageView.layer addAnimation:animation forKey:@"transform.scale"];  }</code></pre>    <p>这段代码没什么说的,应该很容易理解。</p>    <p>2.7 startFire 方法中 (开炮)</p>    <pre>  <code class="language-objectivec">- (void)startFire{      // 每秒喷射的80个      [self.emitterLayer setValue:@1000 forKeyPath:@"emitterCells.emitterCell.birthRate"];      // 开始      self.emitterLayer.beginTime = CACurrentMediaTime();      // 执行停止      [self performSelector:@selector(stopFire) withObject:nil afterDelay:0.1];    }</code></pre>    <p>2.8 stopFire 方法中 (停火)</p>    <pre>  <code class="language-objectivec">- (void)stopFire {      //每秒喷射的个数0个 就意味着关闭了      [self.emitterLayer setValue:@0 forKeyPath:@"emitterCells.emitterCell.birthRate"];    }</code></pre>    <p>最后放两张效果图</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/85576d05af94b461dbb1237673f57e6c.png"> <img src="https://simg.open-open.com/show/5b0d9b23eb9a4b4ee27958a1b03b3e6d.png"></p>    <p> </p>    <p>来自:http://www.cocoachina.com/ios/20161202/18267.html</p>    <p> </p>