你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
iOS CAReplicatorLayer 简单动画
立即下载
用AI写一个
该例子支持:好用才打赏哦
现在下载学习
发布时间:2017-09-06
14人
|
浏览:5451次
|
收藏
|
分享
技术:ios
运行环境:ios8+
概述
CAReplicatorLayer主要是为了高效生成许多相似的图层,可以复制自己子层的layer,并且复制出来的layer和原生子层有同样的属性,位置,形变,动画。
详细
写在最前面,最近在看学习的时候,偶然间发现一个没有用过的`Layer`,于是抽空研究了下,本来应该能提前记录下来,但是苦逼的码农需要租房子,所以耽搁了几天,但是坚持就是胜利,下面就来看看这个强大的`CAReplicatorLayer`,通过这个,可以做很多炫酷的动画,能省很多步骤。 ##### 到底是什么呢? `CAReplicatorLayer`主要是为了高效生成许多相似的图层,可以复制自己子层的layer,并且复制出来的layer和原生子层有同样的属性,位置,形变,动画。 #####相关属性 查看API我们可以看到有一下参数 ``` //拷贝的个数,包括自身 默认为1 @property NSInteger instanceCount; //是否开启景深 @property BOOL preservesDepth; //拷贝的layer执行动画的间隔时间 @property CFTimeInterval instanceDelay; //拷贝的layer执行的3D变换 在前一个的基础上 @property CATransform3D instanceTransform; //拷贝的layer的颜色变换 @property(nullable) CGColorRef instanceColor; //颜色偏移参数 @property float instanceRedOffset; @property float instanceGreenOffset; @property float instanceBlueOffset; //透明度偏移参数 @property float instanceAlphaOffset; ``` #####知识补充 在进行实例之前,如果大家对`UIBezierPath`和`CAAnimation`不太了解的,可以先看看我前面写的关于这两个的文章[iOS 之UIBezierPath](http://www.demodashi.com/demo/11602.html)和[iOS 核心动画 Core Animation浅谈](http://www.demodashi.com/demo/11603.html) ######实战 下面我们先看一组效果图,这是我简单写的几个例子 ![CAReplicatorLayer1.gif](/contentImages/image/jianshu/2525768-abc77e1d6624999d.gif) ######项目文件截图 ![](/contentImages/image/20170906/FoGShuRT3trtKeScbCe.jpg) ######分析 就上面的效果,我们先拿其中一个进行举例说明 就拿这个有20个橙色圆圈的动画来说,之前我也有写个,但是那个时候并不了解`CAReplicatorLayer`,就用的比较麻烦的办法,下面先看看之前的代码 ``` - (void)setupAnimationInLayer:(CALayer *)layer withSize:(CGFloat)size tintColor:(UIColor *)tintColor { NSTimeInterval beginTime = CACurrentMediaTime(); //小圆圈的大小 CGFloat circleSize = size/4.0; CGFloat startY = (layer.bounds.size.height - size)/2.0; CGFloat startX = (layer.bounds.size.width - size)/2.0; CGSize layerSize = layer.bounds.size; CGFloat offeset = (size/2 - circleSize/2) * sinf(M_PI_4); NSArray *rectArray = @[[NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize/2, startY, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize/2 + offeset, layerSize.height/2-offeset - circleSize/2, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize + size/2, layerSize.height/2 - circleSize/2, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize/2 + offeset, layerSize.height/2 + offeset - circleSize/2, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize/2, startY + size-circleSize, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize/2 - offeset, layerSize.height/2 + offeset - circleSize/2, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(startX, layerSize.height/2 - circleSize/2, circleSize, circleSize)], [NSValue valueWithCGRect:CGRectMake(layerSize.width/2 - circleSize/2 - offeset, layerSize.height/2-offeset - circleSize/2, circleSize, circleSize)]]; NSArray *begintimes = @[@(0),@(0.12),@(0.24),@(0.36),@(0.48),@(0.6),@(0.72),@(0.84)]; for (int i = 0;i < rectArray.count;i++) { NSValue *data = rectArray[i]; CGRect rect = data.CGRectValue; CALayer *sublayer = [CALayer layer]; sublayer.frame = rect; sublayer.backgroundColor = [UIColor whiteColor].CGColor; sublayer.cornerRadius = circleSize/2; CAKeyframeAnimation *transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; transformAnimation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 0)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)]]; CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; opacityAnimation.values = @[@(0.5),@(1.0),@(0.5)]; //keyTimes这个可选参数可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的 // opacityAnimation.keyTimes CAAnimationGroup *groupAnimation = [CAAnimationGroup animation]; groupAnimation.duration = 1; groupAnimation.removedOnCompletion = NO; groupAnimation.repeatCount = HUGE_VALF; groupAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; groupAnimation.animations = @[transformAnimation,opacityAnimation]; groupAnimation.beginTime = beginTime + [begintimes[i]doubleValue]; // groupAnimation.timeOffset = [timeOffeset[i] doubleValue]; [layer addSublayer:sublayer]; [sublayer addAnimation:groupAnimation forKey:nil]; } } ``` 在上面的代码中,我用了一个数组`rectArray `来装后面圆圈的位置,然后在用了一个`for`循环,来依次添加圆圈的`layer`,并且大家注意,在代码中我还有一个数组`begintimes `,这个在后面的`CAAnimationGroup `中用到了,用来间隔圆圈执行动画。虽然整体看上去代码并不多,但是其中比较麻烦的就是在计算坐标信息上。 ######CAReplicatorLayer 简单解决 在接触到`CAReplicatorLayer `后,就不用这么麻烦了,20个圆圈,我们可以通过复制`instanceCount `这个来进行实现,执行的时间间隔我们可以通过`instanceDelay `来实现,当然还有一个最重要的就是其位置。查看属性,我们会发现,`CAReplicatorLayer `有一个属性`instanceTransform`,就是进行`3D`变换,要形成一个圆形的环状,我们可以对其进行`Z`轴旋转,从而达到我们想要的效果。那么每一个所旋转的角度是多少呢?计算一下,就是20个圆圈平分`2*M_PI`,所以`3D`变换的代码应该是这样的 ``` CATransform3D transform = CATransform3DIdentity; transform = CATransform3DRotate(transform, M_PI / 10.0, 0, 0, 1); ``` 废话不多说,我们来看看新的解决方案的代码 ``` //一串圈圈,依次变大变小 透明度也变化 - (void)ballSpinFadeAnimationLayer:(CALayer *)layer withSize:(CGSize)size tintColor:(UIColor *)tintColor { CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer]; replicatorLayer.frame = CGRectMake(0, 0, layer.frame.size.width-40, layer.frame.size.height-40); replicatorLayer.backgroundColor = [UIColor whiteColor].CGColor; [layer addSublayer:replicatorLayer]; CALayer *ballLayer = [CALayer layer]; ballLayer.frame = CGRectMake((CGRectGetWidth(replicatorLayer.frame) - 10)/2.0, 0, 10, 10); ballLayer.backgroundColor = tintColor.CGColor; ballLayer.cornerRadius = 5.0; CAKeyframeAnimation *transformAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; transformAnimation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 0)],[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)]]; CAKeyframeAnimation *opacityAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"]; opacityAnimation.values = @[@(0.5),@(1.0),@(0.5)]; //opacityAnimation.keyTimes //keyTimes这个可选参数可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的 CAAnimationGroup *groupAnimation = [CAAnimationGroup animation]; groupAnimation.duration = 1; groupAnimation.removedOnCompletion = NO; groupAnimation.repeatCount = HUGE_VALF; //匀速 groupAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; groupAnimation.animations = @[transformAnimation,opacityAnimation]; [ballLayer addAnimation:groupAnimation forKey:@""]; //绕Z轴旋转M_PI / 10.0 下面复制20个 刚好是一圈 2*M_PI CATransform3D transform = CATransform3DIdentity; transform = CATransform3DRotate(transform, M_PI / 10.0, 0, 0, 1); [replicatorLayer addSublayer:ballLayer]; replicatorLayer.instanceCount = 20; replicatorLayer.instanceTransform = transform; replicatorLayer.instanceDelay = 0.05; } ``` 对比之下,明显发现简单很多,而且思路也很清晰。 下面我们再对第一个心形动画进行分析一下: 这个心形动画截图没有截完全,其效果我简单描述下,从中心最凹处每隔一个时间段吐出一个圆圈,然后每一个都按照心形的轨迹进行运动。我们就不可能通过`instanceTransform `来创建轨迹,因为这个是在初始化的时候就已经创建好其位置了。所以我们只能在其复制的`layer`上想办法。可以这样来思考,就是复制的`layer`每隔一个时间段就开始去执行心形动画。那么心形动画我们怎么去实现呢?由于这是一个不规则的图形,而且是曲线,所以我们想到了`二次贝塞尔曲线`,我们可以通过两个`二次贝塞尔曲线`来进行拼接。 下面我们来看完整的代码 ``` //爱心类型 - (void)loveAnimationLayer:(CALayer *)layer withSize:(CGSize)size tintColor:(UIColor *)tintColor { CAReplicatorLayer *replicatorLayer = [CAReplicatorLayer layer]; replicatorLayer.frame = CGRectMake(0, 0, layer.frame.size.width, layer.frame.size.height); replicatorLayer.backgroundColor = [UIColor whiteColor].CGColor; [layer addSublayer:replicatorLayer]; CALayer *lineBallLayer = [CALayer layer]; lineBallLayer.backgroundColor = tintColor.CGColor; lineBallLayer.cornerRadius = 5; lineBallLayer.frame = CGRectMake((size.width - 10)/2.0, 20, 10, 10); UIBezierPath *tPath = [UIBezierPath bezierPath]; [tPath moveToPoint:CGPointMake(size.width/2.0, 25)]; //二次贝塞尔曲线 [tPath addQuadCurveToPoint:CGPointMake(size.width/2.0, 100) controlPoint:CGPointMake(size.width/2.0 + 80, -10)]; [tPath addQuadCurveToPoint:CGPointMake(size.width/2.0, 25) controlPoint:CGPointMake(size.width/2.0 - 80, -10)]; [tPath closePath];//封闭路径 CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; animation.path = tPath.CGPath;//根据path路径来进行动画 animation.duration = 8;//动画时间 animation.repeatCount = HUGE;//一直重复动画 [lineBallLayer addAnimation:animation forKey:@""];//key可以不设置 [replicatorLayer addSublayer:lineBallLayer]; // replicatorLayer.instanceColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor; replicatorLayer.instanceGreenOffset = -0.03; // 颜色值递减。 replicatorLayer.instanceRedOffset = -0.02; // 颜色值递减。 replicatorLayer.instanceBlueOffset = -0.01; // 颜色值递减。 replicatorLayer.instanceCount = 40;//复制lineBallLayer 40个 replicatorLayer.instanceDelay = 0.2;//每个复制对象执行path路径动画的时间间隔 前一个和后一个之间 } ``` 其中我对颜色也进行了递减,这样看到的效果更加明显。 ######写在最后 `CAReplicatorLayer `确实是个好东西,之前孤陋寡闻了。希望对各位有用
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
0
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
敷衍丶尘世
16
例子数量
615
帮助
43
感谢
评分详细
可运行:
4.5
分
代码质量:
4.5
分
文章描述详细:
4.5
分
代码注释:
4.5
分
综合:
4.5
分
作者例子
iOS 仿支付宝密码支付
iOS 九宫格手势密码
iOS CAReplicatorLayer 简单动画
iOS 之UIBezierPath
iOS 核心动画 Core Animation浅谈
iOS CoreImage之滤镜简单使用
iOS UIButton文字和图片间距随意调整
iOS 简单引导界面
iOS 两种不同的图片无限轮播
iOSQuart2D绘图之UIImage简单使用
iOS 自定义键盘
iOS 自定义转场动画浅谈
iOS Core ML与Vision初识
iOS 11之Vision人脸检测
iOS之基于FreeStreamer的简单音乐播放器(模仿QQ音乐)
iOS 音频视频图像合成那点事