让CALayer的shadowPath跟随bounds一起做动画改变

前言

在iOS开发中,我们经常需要给视图添加阴影效果,最简单的方法就是通过设置CALayer的shadowColor、shadowOpacity、shadowOffset和shadowRadius这几个属性可以很方便的为 UIView 添加阴影效果。但是如果单用这几个属性会导致离屏渲染(Offscreen Rendering),而且CoreAnimation在每一帧绘制阴影的时候都需要递归遍历所有sublayer的alpha通道从而精确的计算出阴影的轮廓,这是非常消耗性能的,从而导致了动画的卡顿。

为了尽可能地减小离屏渲染带来的性能影响,我们可以利用CALayer的另外一个属性shadowPath,这个属性的官方文档是这么描述的:

If you specify a value for this property, the layer creates its shadow using the specified path instead of the layer’s composited alpha channel. The path you provide defines the outline of the shadow. It is filled using the non-zero winding rule and the current shadow color, opacity, and blur radius.

可以看到设置了这个属性以后CALayer在创建其shadow的时候不在遍历sublayer的alpha通道,而是直接用这个属性所指定的路径作为阴影的轮廓,这样就减少了非常多的计算量。

然而这里会有一个问题,shadowPath并不会跟随CALayer的bounds属性进行变化,所以在layer的bounds产生变化以后需要手动更新shadowPath才能让其适配新的bounds。

为了解决这个问题,在使用AutoLayout以前,因为bounds都是手动计算出来的,我们可以很容易的直接设定新的shadowPath,而使用了AutoLayout以后,我们则只能在UIView的layoutSubivews方法中才能获得更新后的bounds。

而且文档中还做了如下描述:

Unlike most animatable properties, this property (as with all CGPathRef animatable properties) does not support implicit animation.

这说明该变量是不支持隐式动画的,也就是说当我们直接设置CALayer的shadowPath属性后,系统并不会自动的提交隐式的CATransaction动画。

为了解决了这个问题,我们需要通过CATransaction显示地指定shadowPath的动画效果,同时为了和bounds的动画效果保持一致,我们需要获取bounds的动画属性。

考虑了以上两点问题以后,我们就可以用如下方法实现让CALayer的shadowPath跟随bounds一起做动画改变。

实现方法

为实现本文的思路,我们需要创建一个一个UIView的子类并且重写其layoutSubivew方法。

// Subclass of UIView
- (void)layoutSubviews {
    [super layoutSubviews];
    // 获取CALayer的bounds属性的隐式动画属性
    CAAnimation *animation = [self.layer animationForKey:@"bounds.size"];
    if (animation) {
        // 为shadowPath属性显示创建一个CATransaction操作
        [CATransaction begin];
        // 设置用获取到的bounds动画属性设置相关参数
        [CATransaction setAnimationDuration:animation.duration];
        [CATransaction setAnimationTimingFunction:animation.timingFunction];
        // 通过CABasicAnimation类来为shadowPath添加动画,当该CABasicAnimation的所有属性都为nil时
        // 其会选择从shadowPath的原值动画过渡至新值
        CABasicAnimation *shadowPathAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
        // 将动画添加至layer的渲染树
        [self.layer addAnimation:shadowPathAnimation forKey:@"shadowPath"];
        [CATransaction commit];
    }
    self.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.layer.bounds].CGPath;
}

本文个人博客地址: http://wty.im/2016/09/26/let-shadow-path-animate-with-layer-bounds/
Github: https://github.com/wty21cn/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值