浅汇-iOS 动画

        在iOS开发中,制作动画效果是最让开发者享受的环节之一。一个设计严谨、精细的动画效果能给用户耳目一新的效果,吸引他们的眼光 —— 这对于app而言是非常重要的。我们总是追求更为酷炫的实现,如果足够仔细,我们不难发现一个好的动画通过步骤分解后本质上不过是一个个简单的动画实现。本文就个人搜集的一些动画相关的理论和实践知识做个小结,不足之处请勿见怪。


理论

      UIView只是CALyer之上的封装,更准确的来说,UIView是CALyer的简版封装,加上事件处理的集合类。CALayer是QuartzCore库内的类,是iOS上最基本的绘制单元。其次,我们知道iOS平台的Cocoa Touch 是源于OS X平台的Cocoa),是在Cocoa的基础上添加了适用于移动手机设备的手势识别、动画等特性;但从底层实现上来说,Cocoa Touch与Cocoa共用一套底层的库,其中就包括了QuartCore.framework;但QuartCore.framework一开始就是为OS X设计的,所以其中有部分特性是不适合做移动设备开发的,比如最重要的坐标系统。因此,我们也就不难理解为何UIView/NSView在CALayer上做了一层封装。

基于UIView实现的动画

简单的Block动画

[UIView animateWithDuration:0.2 animations:^{  }]; [UIView animateWithDuration:0.5f animations:^{  } completion:^(BOOL finished) { //    }];

UIView [begin commit]

_demoView.frame = CGRectMake(0, SCREEN_HEIGHT/2-50, 50, 50); [UIView beginAnimations:nil context:nil]; [UIView setAnimationDuration:1.0f]; _demoView.frame = CGRectMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-50, 50, 50); [UIView commitAnimations];

弹性动画

[UIView animateWithDuration:0.8 delay:0  usingSpringWithDamping:0.5 initialSpringVelocity:6  options:UIViewAnimationOptionCurveEaseOut animations:^{  // } completion:^(BOOL finished) {  }];    //参数:持续时间,延迟时间,阻尼系数,初始速度

关键帧动画(中间可以添加合适多的帧来做不同的衔接动画)

UIView animateKeyframesWithDuration:3.f delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ [UIView addKeyframeWithRelativeStartTime:0.0 relativeDuration:0.8 animations:^{ // }]; [UIView addKeyframeWithRelativeStartTime:0.8 relativeDuration:1.6 animations:^{ // }];                                                              } completion:^(BOOL finished) { //                              }];

CALayer动画

值得注意的是  CASpringAnimation 是 CABasicAnimation 的子类用于实现弹性动画的效果。

常用属性

duration : 动画的持续时间

beginTime : 动画的开始时间

repeatCount : 动画的重复次数

autoreverses : 执行的动画按照原动画返回执行

timingFunction : 控制动画的显示节奏系统提供五种值选择,

分别是:

kCAMediaTimingFunctionLinear 线性动画

kCAMediaTimingFunctionEaseIn 先慢后快(慢进快出)

path:关键帧动画中的执行路径

type : 过渡动画的动画类型,系统提供了四种过渡动画。

kCATransitionFade 渐变效果

kCATransitionMoveIn 进入覆盖效果

subtype : 过渡动画的动画方向

kCATransitionFromRight 从右侧进入

kCATransitionFromLeft 从左侧进入

基础动画主要提供了对于CALayer对象中的可变属性进行简单动画的操作。比如:位移、透明度、缩放、旋转、背景色等等。

重要属性

fromValue : keyPath对应的初始值

toValue : keyPath对应的结束值

基础动画(CABaseAnimation)

0:1  1:0  实现下拉剪头的展开和收起

CABasicAnimation* rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; rotationAnimation.duration = 0.3f; rotationAnimation.repeatCount = 1; rotationAnimation.autoreverses = NO; rotationAnimation.fromValue = [NSNumber numberWithFloat: beginValue*M_PI]; rotationAnimation.toValue = [NSNumber numberWithFloat:endValue*M_PI]; rotationAnimation.removedOnCompletion = NO; rotationAnimation.fillMode = kCAFillModeForwards; rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; [pinLayer addAnimation:rotationAnimation forKey:@"revItUpAnimation"];

关键帧动画(CAKeyframeAnimation

CAKeyframeAnimation和CABaseAnimation都属于CAPropertyAnimatin的子类。`CABaseAnimation只能从一个数值(fromValue)变换成另一个数值(toValue),而CAKeyframeAnimation则会使用一个NSArray保存一组关键帧。 `

重要属性

values : 就是上述的NSArray对象。里面的元素称为”关键帧”(keyframe)。动画对象会在指定的时间(duration)内,依次显示values数组中的每一个关键帧

path : 可以设置一个CGPathRef\CGMutablePathRef,让层跟着路径移动。path只对CALayer的anchorPoint和position起作用。如果你设置了path,那么values将被忽略。

keyTimes : 可以为对应的关键帧指定对应的时间点,其取值范围为0到1.0,keyTimes中的每一个时间值都对应values中的每一帧.当keyTimes没有设置的时候,各个关键帧的时间是平分的。

组合动画:

CAKeyframeAnimation *anima1 = [CAKeyframeAnimation animationWithKeyPath:@"position"]; NSValue *value0 = [NSValue valueWithCGPoint:CGPointMake(0, SCREEN_HEIGHT/2-50)]; NSValue *value1 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/3, SCREEN_HEIGHT/2-50)]; NSValue *value2 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH/3, SCREEN_HEIGHT/2+50)]; NSValue *value3 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2+50)]; NSValue *value4 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH*2/3, SCREEN_HEIGHT/2-50)]; NSValue *value5 = [NSValue valueWithCGPoint:CGPointMake(SCREEN_WIDTH, SCREEN_HEIGHT/2-50)]; anima1.values = [NSArray arrayWithObjects:value0,value1,value2,value3,value4,value5, nil]; //缩放动画 CABasicAnimation *anima2 = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; anima2.fromValue = [NSNumber numberWithFloat:0.8f]; anima2.toValue = [NSNumber numberWithFloat:2.0f]; //旋转动画 CABasicAnimation *anima3 = [CABasicAnimation animationWithKeyPath:@"transform.rotation"]; anima3.toValue = [NSNumber numberWithFloat:M_PI*4]; //组动画 CAAnimationGroup *groupAnimation = [CAAnimationGroup animation]; groupAnimation.animations = [NSArray arrayWithObjects:anima1,anima2,anima3, nil]; groupAnimation.duration = 4.0f; [_demoView.layer addAnimation:groupAnimation forKey:@"groupAnimation"];

过渡动画(CATransition) 多数为私有的API使用后`无法上架app`。

私有API提供了其他很多非常炫的过渡动画,比如@”cube”、@”suckEffect”、@”oglFlip”、 @”rippleEffect”、@”pageCurl”、@”pageUnCurl”、@”cameraIrisHollowOpen”、@”cameraIrisHollowClose”等。

粒子动画

transform动画

transform是一个非常重要的属性,它在矩阵变换的层面上改变视图的显示效果,完成旋转、形变、平移等等操作。在它被修改的同时,视图的frame也会被真实改变。有两个数据类型用来表示transform,分别是CGAffineTransform和CATransform3D。前者作用于UIView,后者为layer层次的变换类型。基于后者可以实现更加强大的功能。

对于想要了解矩阵变换是如何作用实现的,可以参考这篇博客:CGAffineTransform 放射变换

在开始使用transform实现你的动画之前,我先介绍几个常用的函数:

/// 用来连接两个变换效果并返回。返回的t = t1 * t2 CGAffineTransformConcat(CGAffineTransform t1, CGAffineTransform t2) /// 矩阵初始值。[ 1 0 0 1 0 0 ] CGAffineTransformIdentity /// 自定义矩阵变换,需要掌握矩阵变换的知识才知道怎么用。参照上面推荐的原理链接 CGAffineTransformMake(CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty) /// 旋转视图。传入参数为 角度 * (M_PI / 180)。等同于 CGAffineTransformRotate(self.transform, angle) CGAffineTransformMakeRotation(CGFloat angle) CGAffineTransformRotate(CGAffineTransform t, CGFloat angle) /// 缩放视图。等同于CGAffineTransformScale(self.transform, sx, sy) CGAffineTransformMakeScale(CGFloat sx, CGFloat sy) CGAffineTransformScale(CGAffineTransform t, CGFloat sx, CGFloat sy) /// 缩放视图。等同于CGAffineTransformTranslate(self.transform, tx, ty) CGAffineTransformMakeTranslation(CGFloat tx, CGFloat ty) CGAffineTransformTranslate(CGAffineTransform t, CGFloat tx, CGFloat ty) 特殊地,transform属性默认值为CGAffineTransformIdentity,可以在形变之后设置该值以还原到最初状态 样例 self.demoImageView.transform = CGAffineTransformIdentity;

transform严格的说不是一种动画,而是动画中的一部分操作,我拿出来说是因为它同时出现在了UIView 动画和CALayer动画中。

一些应用

- 利用上面CALayer 基础动画的代码实现下拉剪头的展开和收起,还可以实现时钟指针的旋转

  pinLayer = [CALayer layer]; [pinLayer setBounds:CGRectMake(0, 0, 14, 8)]; [pinLayer setContents:(id)[UIImage imageNamed:@"downArrow.png"].CGImage]; [pinLayer setPosition:CGPointMake(305*NEWX,20)]; [pinLayer setAnchorPoint:CGPointMake(0.5, 0.5)]; [behindBgView.layer addSublayer:pinLayer];

输入框在输入错误信息时的摇晃效果

利用CAShapeLayer 和CABasicAnimation 可以实现加载动画

iOS渲染视图的层级图

- UIKit:最常用的视图框架,封装度最高,都是OC对象

- CoreAnimation:提供强大的2D和3D动画效果

- CoreGraphics:主要绘图系统,常用于绘制自定义视图,纯C的API,使用Quartz2D做引擎

- CoreImage:给图片提供各种滤镜处理,比如高斯模糊、锐化等

- OpenGL-ES:主要用于游戏绘制,但它是一套编程规范,具体由设备制造商实现

更多内容可以点击(iOS开发UI篇---iOS Core Animation 总结)


小结

事实告诉我们动画是要靠设计的,你看我上面的动画抽的一笔,但事实上用同样的代码可以写出很漂亮的动画。

一篇很棒的动画总结文章

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏進无尽的文章

绘图-几种基本统计图的实现分析

在开发中我们会遇到各种统计图,或者各种绘图,本文通过对基本三大统计图:折线图、柱状图、扇形图的实现来掌握基本统计图的绘制,在下一篇文中会带来复杂一些的绘图案例分...

1791
来自专栏何俊林

Android开发之贝塞尔曲线进阶篇(仿直播送礼物,饿了么购物车动画)

今天来自李晨玮分享的直播礼物效果Demo。对于直播中送车,点赞都有借鉴意义。李晨玮的简书为:http://www.jianshu.com/u/b2df0a5ea...

5118
来自专栏向治洪

React Native仿美团下拉菜单

在很多产品中都会涉及到下拉菜单选择功能,用的最好的当属美团了,其效果如下: ? 要实现上面的效果,在原生中比较好做,直接使用PopWindow组件即可。如果使...

7445
来自专栏练小习的专栏

制作高大上的Canvas粒子动画

制作粒子动画效果要解决两个问题:一个是粒子动画轨迹,另外一个是粒子执行动画的时机。 首先来看下我们准备要做的粒子动画效果是怎么样的~ 是这样(粒子漂浮): ...

48610
来自专栏HT

HTML5版的String Avoider小游戏

HTML5版的String Avoider小游戏 http://www.newgrounds.com/portal/view/300760 蛮简单也蛮考验耐心,...

2158
来自专栏Guangdong Qi

iOS 连续动画效果(让APP动起来)

2163
来自专栏Crossin的编程教室

【编程课堂】海龟作图

0、前言 turtle 是 python 内置的一个比较有趣味的模块,俗称 海龟作图,它是基于 tkinter 模块打造,提供一些简单的绘图工具,海龟作图最初...

4256
来自专栏Coco的专栏

神奇的 conic-gradient 圆锥渐变

2224
来自专栏jojo的技术小屋

原 canvas小案例集合(小画板、画的回

作者:汪娇娇 日期:2016.12.8 在现在这个公司呆了4个多月,也是研究了canvas将近4个月,前两周心里就痒痒的想写这方面的博客,但一直没时间。可一直拖...

5548
来自专栏前端架构与工程

必应首页平铺背景图片的实现方案

近期某个项目中需要实现以下需求: 保持背景图片原始宽高比; 如果屏幕宽高比与背景图片宽高比不一致,则以图片中心为基点等比缩放背景图片,以适应屏幕尺寸。 以上需求...

2135

扫码关注云+社区