longxdragon's blog

基于CAGradientLayer的闪烁动画

CAGradientLayer是CALayer的子类,专门绘制渐变色的图层。Apple官方文档是这么解释的:“The CAGradientLayer class draws a color gradient over its background color, filling the shape of the layer (including rounded corners)”。

巧妙的运用CAGradientLayer可以实现一些美工上的功能效果,而且效率上也很高。废话不多说,先看Gif图:


gif

是不是有iPhone滑动解锁文字的feel?在没有想到用CAGradientLayer之前,确实难以找到切入点,但如果想到CAGradientLayer来实现的话,就会很简单,直接上源码(这边我主要是在自定义的Label中去实现):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 创建CAGradientLayer
self.gradientLayer = [CAGradientLayer layer];
self.gradientLayer.frame = self.bounds;
// 设置梯度颜色
self.gradientLayer.colors = @[(__bridge id)[[UIColor whiteColor] colorWithAlphaComponent:0.5].CGColor,
(__bridge id)[UIColor whiteColor].CGColor,
(__bridge id)[[UIColor clearColor] colorWithAlphaComponent:0.5].CGColor];
// 设置梯度颜色的位置
self.gradientLayer.locations = @[@(0), @(0.05), @(0.1)];
// 这是颜色渐变的方向
self.gradientLayer.startPoint = CGPointMake(0, 0);
self.gradientLayer.endPoint = CGPointMake(1, 0);
// 设置为mask,iOS8之后,也可以设置self.maskView
self.layer.mask = self.gradientLayer;

代码很简单,主要就是创建CAGradientLayer对象,并进行一些属性设置。但有几点还是很重要的:
1、colorslocations属性是关键,两者的配合可以确定的在对应的位置绘制不同的颜色,而位置之间的过度颜色,CAGradientLayer会绘制出渐变的效果。(颜色也可以拥有透明度哦。。。)。locations的取值范围为[0, 1],并不是以Frame为标准。
2、startPointendPoint属性能够确定颜色渐变的方向,默认(0,0)为左上角,(1,1)为右下角。
3、将CAGradientLayer对象赋值给layer的mask属性。

##什么是Mask?
Apple的注释是这样的:

A layer whose alpha channel is used as a mask to select between the layer’s background and the result of compositing the layer’s contents with its filtered background.

简单来理解就是:当一个有alpha通道的图层作为另一个layer的mask属性后,该图层只会保留和另一个layer非透明区域重叠的部分。

该实例中,我们用自定义Label去mask一个白色透明度从0.5到0再到0.5的CAGradientLayer,效果就会是,CAGradientLayer中间透明度为0的区域,Label会完全显示,而0.5的区域会让Label的文字显得暗淡点。

没有设置mask的效果




设置mask后的效果


是不是发现已经离开始的动画很接近了?好了!难点解决!由于CAGradientLayer的colorslocations属性都支持隐形动画。下面直接用CABasicAnimation来实现动画效果即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
- (void)doAnimation {
[self.gradientLayer removeAnimationForKey:@"slide"];
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"locations"];
// 设置开始值
animation.fromValue = @[@(0), @(0.05), @(0.1)];
// 这是结束值
animation.toValue = @[@(0.9), @(0.95), @(1)];
animation.duration = _flickeringAnimationDuration;
animation.removedOnCompletion = YES;
animation.delegate = self;
[self.gradientLayer addAnimation:animation forKey:@"slide"];
}
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
// 重复动画
if (flag) {
[self doAnimation];
}
}

这边我实现的思路是改变颜色值梯度的位置,模拟出高亮的地方在移动的感觉。是不是很炫酷呢?!
这边是源码LXFlickeringLabel,欢迎小伙伴们下载并指出问题(什么问题都可以,包括代码规范什么的都可以!^_^!)。

##总结
1、CAGradientLayer是可以创建渐变效果的图层,合理的使用可以调配出炫彩的效果,摆脱繁多的UI图片。
2、理解mask属性,并用其来实现对部分区域的遮挡效果。

##尾巴
好吧!其实GitHub中已经有了一个实现高亮效果的开源项目Shimmer,有兴趣的小伙伴可以研究下。我也在踩着前人的肩膀前行。。。