你的浏览器禁用了JavaScript, 请开启后刷新浏览器获得更好的体验!
首页
热门
推荐
精选
登录
|
注册
iOS 核心动画 Core Animation浅谈
立即下载
用AI写一个
该例子支持:好用才打赏哦
现在下载学习
发布时间:2017-09-06
13人
|
浏览:7107次
|
收藏
|
分享
技术:ios
运行环境:ios8+
概述
主要是分析核心动画,iOS 中的核心动画又分为下面几种:基础动画、关键帧动画、动画组、转场动画、弹簧动画。
详细
######前记 关于实现一个iOS动画,如果简单的,我们可以直接调用`UIView`的代码块来实现,虽然使用`UIView`封装的方法很方便,但是这只能用于一些简答的动画,如果是一些复杂的动画呢?这就不得不去研究下核心动画`Core Animation`(包含在`Quartz Core`框架中)了。这这之前我们必须了解,`CALayer`就包含在`Quartz Core`框架中,这是一个跨平台的框架,既可以用在iOS中又可以用在Mac OS X中。在使用`Core Animation`开发动画的本质就是将`CALayer`中的内容转化为位图从而供硬件操作,所以要熟练掌握动画操作必须熟悉`CALayer`,关于`CALayer`就不在这里讲了。今天主要是分析核心动画,iOS 中的核心动画又分为下面几种:基础动画、关键帧动画、动画组、转场动画、弹簧动画。下面我们先来了解下各个动画之间的关系 ![core_animation.jpeg](/contentImages/image/jianshu/2525768-0e3514862294fd0e.jpeg) #####动画简介 ######CAAnimation ``` @interface CAAnimation : NSObject
{ @private void *_attr; uint32_t _flags; } ``` 这是核心动画的基类,不能直接使用,主要负责动画的时间、速度等,从上面可以看出是准守`CAMediaTiming`协议的。 ######CAPropertyAnimation 属性动画的基础类,继承自`CAAnimation`,不能直接使用。何谓属性动画呢?即通过修改属性值就可以产生动画效果。 ######CAAnimationGroup 动画组,继承自`CAAnimation`,顾名思义就是一种组合动画,可以通过动画组来进行所有动画行为的统一控制,组中所有动画效果可以并发执行。 ######CATransition 转场动画,继承自`CAAnimation`,主要是通过滤镜来进行动画的效果设置 ######CABasicAnimation 基础动画,继承自`CAPropertyAnimation`,通过属性控制动画的参数,只要初始状态和结束状态 ######CAKeyframeAnimation 关键帧动画,继承自`CAPropertyAnimation`,也是通过属性控制动画参数,但是与基础动画不同的是有多个控制状态,并且可以通过`path`来实现动画 ######CASpringAnimation 弹簧动画,是在iOS 9中引入的,继承自`CABasicAnimation`,用于制作弹簧动画 #####动画使用 在使用动画之前,先补充个知识点---[UIBezierPath](http://www.demodashi.com/demo/11602.html), 这在动画使用的过程中会经常用到 ######核心动画 要使用核心动画,我们必须先了解下其属性,这里我们先看其遵守的协议`
` | 属性 | 说明 | | -------------- | ---------------------------------------- | | beginTime | 指定动画开始的时间。开始延迟几秒的话,设置为`CACurrentMediaTime() + 秒数` 的方式即可 | | duration | 动画的时长 | | speed | 动画的速度 | | timeOffset | [详细说明](http://www.cocoachina.com/programmer/20131218/7569.html) | | repeatCount | 动画重复的次数,如果要一直持续设置为`HUGE_VALF`即可 | | repeatDuration | 设置动画的时间。在该时间内动画一直执行,不计次数 | | autoreverses | 动画结束时是否执行逆动画 | | fillMode | 分四种情况,分别为`kCAFillModeForwards`、`kCAFillModeBackwards`、`kCAFillModeBoth`、`kCAFillModeRemoved`,决定当前对象在非active时间段的行为,比如动画开始之前或者动画结束之 | `CAAnimation`属性 | 属性 | 说明 | | ------------------- | ---------------------------------------- | | timingFunction | 速度控制函数,控制动画运行的节奏 | | removedOnCompletion | 默认为`YES`,代表动画执行完毕后就从图层上移除,图形会恢复到动画执行前的状态。如果想让图层保持显示动画执行后的状态,那就设置为`NO`,不过还要设置`fillMode`为`kCAFillModeForwards` | 关于`fillMode`的四种情况: - `kCAFillModeRemoved` 默认值,动画结束后,layer会恢复到之前的状态 - `kCAFillModeForwards` 当动画结束后,layer会一直保持着动画最后的状态,而`removedOnCompletion`的默认属性值是 `YES`,所以为了使动画结束之后layer保持结束状态,应将`removedOnCompletion`设置为`NO`。 - `kCAFillModeBackwards` 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。 - `kCAFillModeBoth` 这个其实就是上面两个的合成,动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态 关于速度`CAMediaTimingFunction `控制的四种情况 - `kCAMediaTimingFunctionLinear`(线性):匀速,给你一个相对静态的感觉 - `kCAMediaTimingFunctionEaseIn`(渐进):动画缓慢进入,然后加速离开 - `kCAMediaTimingFunctionEaseOut`(渐出):动画全速进入,然后减速的到达目的地 - `kCAMediaTimingFunctionEaseInEaseOut`(渐进渐出):动画缓慢的进入,中间加速,然后减速的到达目的地。这个是默认的动画行为。 ######属性动画 从上图中我们知道,属性动画是继承自核心动画,在其API中我们可以看到有如下函数和属性 ``` + (instancetype)animationWithKeyPath:(nullable NSString *)path; @property(nullable, copy) NSString *keyPath; ``` 其中都有`keyPath`,这又是什么呢?这就是属性动画与动画组和转场动画不同之处。通过指定`CALayer`的一个属性名称为`keyPath`(NSString类型),并且对`CALayer`的这个属性的值进行修改,达到相应的动画效果。比如,指定`@"opacity"`为`keyPath`,就修改`CALayer`的`opacity`属性的值,以达到透明度变化的动画效果 下面我们列举一些常用的`animationWithKeyPath`值 | 常用值 | 说明 | 使用方式 | | -------------------- | -------------- | ---------------------------------------- | | transform | 3D变换 | `[NSValue valueWithCATransform3D:CATransform3DMakeScale(0.5, 0.5, 0)]`,直接进行3D变换 | | transform.scale | 缩放 | @(1.5) ,放大1.5倍 | | transform.scale.x | 宽度缩放 | @(1.5) ,宽放大1.5倍 | | transform.scale.y | 高度缩放 | @(1.5) ,高放大1.5倍 | | transform.rotation.x | 围绕x轴旋转 | @(M_PI) ,x轴旋转180度 | | transform.rotation.y | 围绕y轴旋转 | @(M_PI) ,y轴旋转180度 | | transform.rotation.z | 围绕z轴旋转 | @(M_PI) ,z轴旋转180度 | | position | 位置(中心点的改变) | `[NSValue valueWithCGPoint:CGPointMake(100, 100)]`,中心点变为(100,100) | | opacity | 透明度 | @(0.5) ,透明度变为0.5 | | bounds | 大小的改变 中心点保持不变 | `[NSValue valueWithCGRect:CGRectMake(0, 0, 300, 300)]`,大小变为(300,300) | | cornerRadius | 圆角的设置 | @(5) ,圆角设置为5 | | backgroundColor | 背景颜色变换 | `(id)[UIColor redColor].CGColor`,背景改为红色 | | contents | 可以改变layer展示的图片 | `(id)[UIImage imageNamed:@"12.png"].CGImage`,将UIView的展示图片改为12.png | | strokeStart | 从起始点开始变化 | `fromValue = 0`,`toValue = 1`,为`CAShapeLayer`的属性 | | strokeEnd | 从结束的位置开始变化 | `fromValue = 1`,`toValue = 0.5`,为`CAShapeLayer`的属性 | | path | 根据路径来改变 | `fromValue = (__bridge id)(start.CGPath);`,`toValue = (__bridge id)((end.CGPath))` | ######基础动画 基础动画是继承自属性动画,所以在使用的时候,我们最主要的就是通过属性来控制动画,比如设置初始值、结束值,当然还有核心动画的其他属性。 ``` - (void)showAnimation { CAShapeLayer * circle = [CAShapeLayer layer]; circle.frame = self.view.bounds; // UIBezierPath * circlePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)) radius:self.normalSize.width/2 -1 startAngle:0 endAngle:2*M_PI clockwise:YES]; circle.path = circlePath.CGPath; circle.strokeColor = [UIColor blueColor].CGColor; circle.fillColor = nil; [self.view.layer addSublayer:circle]; //通过圆的strokeStart 改变来进行改变 CABasicAnimation * strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"]; strokeStartAnimation.fromValue = @(0.2); strokeStartAnimation.toValue = @(0); //通过圆的strokeEnd 改变来进行改变 CABasicAnimation * strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; strokeEndAnimation.fromValue = @0.5; strokeEndAnimation.toValue = @(1.0); //通过圆的transform.rotation.z 改变来进行改变 CABasicAnimation * rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotationAnimation.fromValue = @(0); rotationAnimation.toValue = @(-M_PI * 2); //组合动画 CAAnimationGroup * group = [CAAnimationGroup animation]; group.duration = 5; group.removedOnCompletion = NO; group.fillMode = kCAFillModeForwards; group.animations = @[strokeStartAnimation,strokeEndAnimation,rotationAnimation]; [circle addAnimation:group forKey:nil]; } ``` 在上面的基础动画代码中,我只用了最基础的两个属性,`fromValue `和`toValue `,而其它属性呢?由于后面用到了动画组,所以讲其它属性在动画组进行了设置。`[circle addAnimation:group forKey:nil];`这句代码中,`key`我设置的为`nil`,如果不设置为`nil`的时候,是什么意思呢?这个其实就是我们的动画设置了一个`key`,可以用来区别是哪一个动画,在后面我会举例说明。 上面代码对应的效果如下: ![baseAnimation.gif](/contentImages/image/jianshu/2525768-db77cdae88a203a4.gif) ######关键帧动画 关键帧动画也是属性动画,与基础动画最主要不同的是在两个参数上,`NSArray *values`和`CGPathRef path`,通过这个我们可以知晓,关键帧动画可以设置多个控制状态 如下: ``` //用value的方式进行展示动画 - (void)showKeyFrameAnimationWithValues { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; NSValue *key1 = [NSValue valueWithCGPoint:_beginPoint]; NSValue *key2 = [NSValue valueWithCGPoint:CGPointMake(100, 100)]; NSValue *key3 = [NSValue valueWithCGPoint:CGPointMake(150, 50)]; NSValue *key4 = [NSValue valueWithCGPoint:CGPointMake(300, 250)]; animation.values = @[key1,key2,key3,key4]; animation.duration = 5.0; animation.delegate = (id)self; // animation.autoreverses = true;//是否按路径返回 // animation.repeatCount = HUGE;//是否重复执行 animation.removedOnCompletion = NO;//执行后移除动画 animation.fillMode = kCAFillModeForwards; //存储位置 [animation setValue:key4 forKey:@"keyframeAnimationLocation"]; [_fishImageView.layer addAnimation:animation forKey:@"keyframeAnimation_fish"]; } ``` 而且还可以设置路径,这也是其最大的特点 如下: ``` //用CGPathRef的方式进行展示动画 - (void)showKeyFrameAnimationWithPath { CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"]; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:_fishImageView.layer.position]; //三次贝塞尔曲线 [path addCurveToPoint:CGPointMake(300, 200) controlPoint1:CGPointMake(150, 400) controlPoint2:CGPointMake(230, -100)]; animation.path = path.CGPath; animation.duration = 5.0; animation.delegate = (id)self; [_fishImageView.layer addAnimation:animation forKey:@"keyframeAnimation_path_fish"]; } ``` 效果如下,这里就暂时只给出`values`的效果 ![keyanimation.gif](/contentImages/image/jianshu/2525768-6176596fe93277c1.gif) 在上面的两个方法中,对`layer`设置了两个不同的`key`,分别为`keyframeAnimation_fish`和`keyframeAnimation_path_fish` 前面我提到过,通过这个可以判断是哪一种动画,这里我们在动画结束的地方进行区分一下 ``` - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { if ([anim isEqual:[_fishImageView.layer animationForKey:@"keyframeAnimation_fish"]]) { // [CATransaction begin]; // //禁用隐式动画 // [CATransaction setDisableActions:YES]; _fishImageView.layer.position = [[anim valueForKey:@"keyframeAnimationLocation"] CGPointValue]; // //提交事务 // [CATransaction commit]; } else if ([anim isEqual:[_fishImageView.layer animationForKey:@"keyframeAnimation_path_fish"]]) { } } ``` ######动画组 动画组其实很简单,就是将许多动画组合在一起 在上面的基础动画中,我也用到了动画组,下面再贴上一组动画组合效果 ``` //发射 - (void)launchAnimation { CABasicAnimation *animation1 = [CABasicAnimation animationWithKeyPath:@"transform.scale.y"]; animation1.fromValue = @(1.0); animation1.toValue = @(1.5); CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"transform.scale.x"]; animation2.fromValue = @(1.0); animation2.toValue = @(1.5); CABasicAnimation *animation3 = [CABasicAnimation animationWithKeyPath:@"position"]; animation3.fromValue = [NSValue valueWithCGPoint:_ballLayer.position]; animation3.toValue = [NSValue valueWithCGPoint:CGPointMake(self.view.frame.size.width - (30 * 1.3)/2.0 , _ballLayer.position.y - 200)]; CAAnimationGroup *anima = [CAAnimationGroup animation]; anima.animations = @[animation1, animation2,animation3]; anima.duration = 1.0; anima.delegate = (id)self; anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; anima.fillMode = kCAFillModeForwards; anima.removedOnCompletion = NO; [_ballLayer addAnimation:anima forKey:@"group_launch"]; } ``` 在后面的demo里有完整的代码,这里只是截取了部分代码 效果如下: ![groupanimation.gif](/contentImages/image/jianshu/2525768-308c6c0c02afbc1b.gif) ######转场动画 在了解转场动画之前,我们先了解其两个参数,通过这些参数,我们就能很清楚的了解其效果 - `type`转场类型 | 转场动画类型 | 说明 | 常量 | 是否支持方向设置 | | --------------------- | ------------------- | --------------------- | -------- | | 公开API | | | | | fade | 淡出 | `kCATransitionFade` | 是 | | movein | 新视图移动到旧视图上面 | `kCATransitionMoveIn` | 是 | | push | 新视图退出旧视图 | `kCATransitionPush` | 是 | | reveal | 移开旧视图显示新的 | `kCATransitionReveal` | 是 | | 私有API | 苹果未公开的类型,但是目前还是可以用的 | 私有API只能通过下面的字符串进行访问 | | | cube | 立体翻转 | | 是 | | oglFlip | 翻转 | | 是 | | suckEffect | 收缩 | | 否 | | rippleEffect | 水滴波纹效果 | | 否 | | pageCurl | 向上翻页效果 | | 是 | | pageUnCurl | 向下翻页效果 | | 是 | | cameraIrisHollowOpen | 摄像头打开效果 | | 否 | | cameraIrisHollowClose | 摄像头关闭效果 | | 否 | - `subtype`动画子类型 | 属性 | 说明 | | ----------------------- | ---- | | kCATransitionFromRight | 从右 | | kCATransitionFromLeft | 从左 | | kCATransitionFromTop | 从顶部 | | kCATransitionFromBottom | 从底部 | 在了解上面两个属性后,对应转场动画,就差不多了 部分代码如下 ``` - (void)transition:(BOOL)next { CATransition *transition = [CATransition animation]; transition.type = @"cube"; if (next) { transition.subtype = kCATransitionFromLeft; } else { transition.subtype = kCATransitionFromRight; } transition.duration = 1.0; _imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg",(long)_currentIndex]]; [_imageView.layer addAnimation:transition forKey:@"transitionAnimation"]; } ``` 效果如下 ![transanimation.gif](/contentImages/image/jianshu/2525768-4f8be413ffc17b51.gif) ######弹簧动画 弹簧动画是在iOS 9后才出现的,在这之前,我们可以通过下面的方法来实现 ``` [UIView animateWithDuration:5.0 delay:0 usingSpringWithDamping:0.1 initialSpringVelocity:1.0 options:UIViewAnimationOptionCurveLinear animations:^{ } completion:nil]; ``` iOS 9后苹果公开了这一API,我们先对其中的属性进行分析,因为代码中有注释,所以就直接贴一部分代码 ``` //质量,影响图层运动时的弹簧惯性,质量越大,弹簧拉伸和压缩的幅度越大 positionAnimation.mass = 0.1; //阻尼系数,阻止弹簧伸缩的系数,阻尼系数越大,停止越快 positionAnimation.damping = 2; //刚度系数(劲度系数/弹性系数),刚度系数越大,形变产生的力就越大,运动越快 positionAnimation.stiffness = 50; //初始速率,动画视图的初始速度大小 //速率为正数时,速度方向与运动方向一致,速率为负数时,速度方向与运动方向相反 positionAnimation.initialVelocity = -10; ``` 关于弹簧动画,我也写了一个例子,效果如下 ![springanimation.gif](/contentImages/image/jianshu/2525768-952c4e9a3db63542.gif) ######项目文件截图: ![](/contentImages/image/20170906/kcWBM1r45eVgNCv8Rqu.jpg) ######写在最后 关于核心动画,差不多就简单的介绍这么点,如有什么不对的还望各位多多指教,不甚感激。
本实例支付的费用只是购买源码的费用,如有疑问欢迎在文末留言交流,如需作者在线代码指导、定制等,在作者开启付费服务后,可以点击“购买服务”进行实时联系,请知悉,谢谢
感谢
0
手机上随时阅读、收藏该文章 ?请扫下方二维码
相似例子推荐
评论
作者
敷衍丶尘世
16
例子数量
614
帮助
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 音频视频图像合成那点事