UI进阶 动画
前言:所谓动画,即应用界面上展示的各种过渡效果,不过其实没有动画并不影响我们产品的功能实现
一、动画
1、动画可以达到的效果
- 传达状态
- 提高用户对直接操作的感知
- 帮助用户可视化操作的结果
2、使用动画应该注意
- 谨慎添加动画,尤其是在那些不能提供沉浸式用户体验(让人专注在当前由设计者营造的情境下感到愉悦和满足暂时忘记真实世界的情境)的App中。
如果App主要关注一些严肃的任务或者生产性任务,那么动画就显得多余了,还会无端打乱App的使用流程,降低应用的性能,让用户从当前的任务中分心。 - 开发者的自定义动画应该适当符合内置iOS应用的动画。
用户习惯于内置iOS App使用的精细动画。事实上,用户趋向于把视图之间的平滑转换,对设备方向改变的流畅响应和基于物理力学的滚动效果看作是iOS体验的一部分。除非你的应用能够给用户沉浸式的体验—比如游戏(自定义动画应该可以与内置应用的动画相媲美) - 使用风格类型一致的动画。
在App中使用风格类型一致的动画非常重要,可以让用户构建基于使用App获得的用户体验。
二、GIF、风火轮动画
1、UIImageView实现GIF动画
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 // 新建一个现实图片的ImageView 4 UIImageView * showGIFImageView = [[UIImageView alloc] initWithFrame:CGRectMake(50, 100, 314, 300)]; 5 [self.view addSubview:showGIFImageView]; 6 NSMutableArray *imageArray = [NSMutableArray array]; 7 for (int i = 1; i <= 10; i++) { 8 [imageArray addObject:[UIImage imageNamed:[NSString stringWithFormat:@"%d.tiff", i]]]; 9 } 10 11 // 设置GIF图片组 12 showGIFImageView.animationImages = imageArray; 13 // 设置播放速度 14 showGIFImageView.animationDuration = 0.9f; 15 // 设置播放次数,0和负数 -- 无限循环 16 showGIFImageView.animationRepeatCount = 0; 17 // 开始动画 18 [showGIFImageView startAnimating]; 19 }
2、风火轮动画
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 self.view.backgroundColor = [UIColor blackColor]; 4 // 加载旋转的菊花效果[UIActivityIndicatorView实现] 5 // 无需设置frame 6 UIActivityIndicatorView *indicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 7 // 显示在视图中间 8 indicatorView.center = self.view.center; 9 // 开启动画 10 [indicatorView startAnimating]; 11 [self.view addSubview:indicatorView]; 12 }
实现效果:
三、iOS能够实现动画的方式
动画大纲:
1、UIView基础动画
UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画支持。
执行动画的工作由UIView类自动完成,但仍希望在执行动画时通知视图,为此需要将改变属性的代码放在[UIView beginAnimations:nil context:nil]和[UIView commitAnimations]之间。
1.1、改变视图frame
1 #pragma mark - 改变frame 2 - (IBAction)changeFrame:(id)sender { 3 // 第一步:开始UIView动画 4 [UIView beginAnimations:@"move" context:@"改变frame"]; 5 // 第二步:设置动画时长 6 [UIView setAnimationDuration:3.0]; 7 // 第三步:设置UIView动画的代理,不需要遵循协议 8 [UIView setAnimationDelegate:self]; 9 // 第四步:设置相关对象的frame 10 self.testView.frame = CGRectMake(100, 100, 200, 100); 11 // 第五步:结束动画(提交动画效果) 12 [UIView commitAnimations]; 13 } 14 15 #pragma mark - 协议方法 16 #pragma mark - 开始动画 17 // 下面的方法替换了+ (void)setAnimationWillStartSelector:(nullable SEL)selector;方法 18 - (void)animationWillStart:(NSString *)animationID context:(void *)context { 19 NSLog(@"开始ID = %@, context = %@", animationID, context); 20 } 21 22 #pragma mark - 结束动画 23 // 下面的方法替换了 + (void)setAnimationDidStopSelector:(nullable SEL)selector;方法 24 - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { 25 NSLog(@"结束ID = %@, context = %@", animationID, context); 26 }
1.2、改变背景颜色
1 #pragma mark - 改变背景颜色 2 - (IBAction)changeBackgroundColor:(id)sender { 3 [UIView beginAnimations:@"color" context:@"改变颜色"]; 4 [UIView setAnimationDuration:2.0]; 5 [UIView setAnimationDelegate:self]; 6 self.testView.backgroundColor = [UIColor yellowColor]; 7 [UIView commitAnimations]; 8 }
1.3、改变透明度Alpha
1 #pragma mark - 改变透明度 2 - (IBAction)changeAlpha:(id)sender { 3 [UIView beginAnimations:@"alpha" context:@"改变透明度"]; 4 [UIView setAnimationDuration:2.0]; 5 [UIView setAnimationDelegate:self]; 6 self.testView.alpha = 0.2; 7 [UIView commitAnimations]; 8 }
1.4、仿射翻转
1 #pragma mark - 仿射翻转 2 - (IBAction)rotationAction:(id)sender { 3 // 开始动画 4 [UIView beginAnimations:@"rotation" context:@"仿射翻转"]; 5 // 设置动画时长 6 [UIView setAnimationDuration:0.9]; 7 // 设置动画块中的动画属性变化的曲线 8 [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 9 // 设置翻转方向 -- 向上翻页效果 10 [UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.testView cache:YES]; 11 // 设置动画代理 12 [UIView setAnimationDelegate:self]; 13 // 结束动画 14 [UIView commitAnimations]; 15 }
1.5、仿射旋转
1 #pragma mark - 仿射旋转 2 - (IBAction)transformAction:(id)sender { 3 [UIView beginAnimations:@"transform" context:@"仿射旋转"]; 4 [UIView setAnimationDuration:0.7]; 5 // 设置旋转角度 6 CGAffineTransform tranform = CGAffineTransformMakeRotation(3 * M_PI); 7 // 设置旋转动画的对象 8 [self.testView setTransform:tranform]; 9 10 [UIView setAnimationDelegate:self]; 11 [UIView commitAnimations]; 12 }
2、UIView基础动画实现方式二(block)
2.1、简单动画
1 #pragma mark - 简单动画 2 - (IBAction)simpleBlockAnimation:(id)sender { 3 // 第一个参数 -- 设置动画时长 4 // 第二个参数block -- 具体的动画效果 5 // 第三个参数block -- 动画完成后要做的事情 6 __weak typeof(self) weakSelf = self; 7 [UIView animateWithDuration:2.0f animations:^{ 8 // 改变视图中心点 9 weakSelf.testView.center = weakSelf.view.center; 10 } completion:^(BOOL finished) { 11 NSLog(@"动画已完成"); 12 }]; 13 }
2.2、复杂动画
1 #pragma mark - 复杂动画 2 - (IBAction)complexBlockAnimation:(id)sender { 3 /** 4 参数1:动画时长 5 参数2:动画延迟时间 6 参数3:枚举值 -- 动画效果 7 参数4:block -- 要实现的动画效果 8 参数5:block -- 动画完成后要做的事 9 */ 10 __weak typeof(self) weakSelf = self; 11 [UIView animateWithDuration:2.0f delay:1.0f options:UIViewAnimationOptionBeginFromCurrentState animations:^{ 12 // 改变尺寸 13 weakSelf.testView.frame = CGRectMake(100, 100, 100, 100); 14 } completion:^(BOOL finished) { 15 NSLog(@"尺寸缩小"); 16 }]; 17 18 }
2.3、关键帧动画
1 #pragma mark - 关键帧动画 2 - (IBAction)keyFramesAnimation:(id)sender { 3 /** 4 参数1:动画时长 5 参数2:动画延迟时间 6 参数3:枚举值 -- 动画效果 7 参数4:开始动画 8 */ 9 __weak typeof(self) weakSelf = self; 10 [UIView animateKeyframesWithDuration:2.0f delay:1.0f options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{ 11 /** 12 参数1:帧动画的开始时间 13 参数2:帧动画的持续时间 14 */ 15 [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:3.0f animations:^{ 16 // 在这里实现想要的动画效果 17 weakSelf.testView.center = weakSelf.view.center; 18 }]; 19 } completion:^(BOOL finished) { 20 NSLog(@"帧动画完成"); 21 }]; 22 }
2.4、Spring(弹簧)动画
Spring Animation 是一种特殊的动画曲线,自从 iOS 7 开始被广泛应用在系统动画中。
事实上,从 iOS 7 起几乎所有的系统动画都用的是 Spring Animation,包括 App 文件夹打开/关闭效果、键盘弹出效果、UISwitch 控件的开关效果、不同 View Controller 之间的 Push 动画、Modal 出现和消失的动画、Siri 的出现和消失动画,等等
Spring Animation 是线性动画或 ease-out 动画的理想替代品。由于 iOS 本身大量使用的就是 Spring Animation,用户已经习惯了这种动画效果,因此使用它能使 App 让人感觉更加自然,用 Apple 的话说就是「instantly familiar」。此外,Spring Animation 不只能针对位置变化使用,它适用于所有可被添加动画效果的属性。
1 - (void)viewDidLoad { 2 [super viewDidLoad]; 3 self.title = @"Spring动画"; 4 /** 5 参数1:动画时长 6 参数2:延迟时间 7 参数3:弹簧效果值 0-1 数值越小「弹簧」的振动效果越明显 8 参数4:表示初始的速度,数值越大一开始移动越快 9 参数5:枚举值 -- 可选动画效果 10 参数6:动画最终效果 11 参数7:动画完成时要做的事 12 */ 13 14 __weak typeof(self)weakSelf = self; 15 [UIView animateWithDuration:3.0f delay:1.0f usingSpringWithDamping:1.0f initialSpringVelocity:10 options:UIViewAnimationOptionTransitionCurlUp animations:^{ 16 weakSelf.testView.center = weakSelf.view.center; 17 } completion:^(BOOL finished) { 18 NSLog(@"中心点位置改变了"); 19 }]; 20 }
3、CoreAnimation动画(layer动画)实现方式
- CoreAnimation基本介绍
- CoreAnimation动画位于iOS框架的Media层
- CoreAnimation动画实现需要添加QuartzCore.Framework
- CoreAnimation基本上是Layer Animation
- CALayer基本介绍
- CALayer负责绘制,提供UIView 需要展示的内容。不能交互。
UIView负责交互,显示CALayer绘制的内容。 - CALayer(层)是屏幕上的一个矩形区域,在每一个UIView中都包含一个根CALayer,在UIView上的所有视觉效果都是在这个Layer上进行的。
- CALayer外形特征主要包括:
1、层的大小尺寸
2、背景色
3、内容(可以填充图片或者使用Core Graphics绘制的内容)
4、矩形是否使用圆角
5、矩形是否有阴影 - Layer有很多种,最常用也是最基本的是CALayer,当然还包括其他的子类:
CAScrollerLayer 简化显示层的一部分
CATextLayer 文本层
CAGradientLayer、CAShapeLayer等等 - UIView是iOS系统中界面元素的基础,所有的界面元素都是继承自它。它本身完全是由CoreAnimation来实现的。它真正的绘图部分,是由一个CALayer类来管理。UIView本身更像是一个CALayer的管理器,访问它的跟绘图和跟坐标有关的属性,例如frame,bounds等,实际上内部都是在访问它所包含的CALayer的相关属性。
- UIView有个重要属性layer,可以返回它的主CALayer实例。
- UIView的CALayer类似UIView的子View树形结构,也可以向它的layer上添加子layer,来完成某些特殊的表示。即CALayer层是可以嵌套的。
- CALayer负责绘制,提供UIView 需要展示的内容。不能交互。
-
- 渲染:当更新层改变不能立即显示在屏幕上,当所有的层都准备好时,可以调用setNeedsDisplay方法来重绘显示。
- 坐标系统:CALayer的坐标系统比UIView多了一个anchorPoint属性,使用CGPoint结构表示,值域是0~1,是个比例值。这个点是各种图形变换的坐标原点,同时会更改layer的position的位置,它的缺省值是{0.5,0.5},即在layer的中央,如下图。
- 动画的运作:对UIView的subLayer(非主Layer)属性进行更改,系统将自动进行动画生成,动画持续时间的缺省值似乎是0.5秒。
1 #pragma mark - Layer的常用属性 2 // 设置图片为圆角 3 self.testView.layer.cornerRadius = 20; 4 // // 子图层是否相对于父图层裁剪,但如果加上这句话,设置的阴影效果就不显示 5 // self.testView.layer.masksToBounds = YES; 6 // 设置阴影的偏移量 7 self.testView.layer.shadowOffset = CGSizeMake(10, 10); 8 // 设置layer的阴影颜色 9 self.testView.layer.shadowColor = [UIColor grayColor].CGColor; 10 // 设置阴影的透明度 11 self.testView.layer.shadowOpacity = 1; 12 // 设置阴影的模糊度 13 self.testView.layer.shadowRadius = 20; 14 15 // 设置UIView的阴影 16 self.myView.layer.shadowOffset = CGSizeMake(-10, 10); 17 self.myView.layer.shadowColor = [UIColor greenColor].CGColor; 18 self.myView.layer.shadowOpacity = 1; 19 self.myView.layer.shadowRadius = 20; 20
- CoreAnimation基本介绍
- 变换:要在一个层中添加一个3D或仿射变换,可以分别设置层的transform或affineTransform属性。
- 变形:Quartz Core的渲染能力,使二维图像可以被自由操纵,就好像是三维的。图像可以在一个三维坐标系中以任意角度被旋转,缩放和倾斜。CATransform3D的一套方法提供了一些魔术般的变换效果。
- 隐式动画:无需指定任何动画的类型,仅仅改变一个属性,然后Core Animation来决定如何及何时去做动画。
- 显式动画:对一些属性做指定的自定义动画,或者创建非线性动画,比如沿着任意一条曲线移动。
- CoreAnimation作用
与UIView动画比,CoreAnimation能够实现更多复杂、好看、高效的动画效果
1、阴影,圆角,带颜色的边框
2、3D变换
3、透明遮罩
4、多级非线性动画 - CoreAnimation
- CABasicAnimation 基本单一类型的动画
- CAKeyframeAnimation 帧动画
主要操作属性有 keyPath 和 values 值组合 - CAAnimationGroup 组合动画
操作属性:animations 将CAAnimation类型的动画加入数组,FIFO队列的方式执行
3.1、CABasicAnimation基础动画
关键属性:
支持的方式:
注意:当UIView移动到指定位置后,会返回到初始位置,那是因为动画作用在表示层,当动画结束时,动画会被移除掉,此刻模型层Layer还没有变化,所以最终会回到初始位置。
解决办法:
1 // 动画执行完毕后不从图层上移除,图形不会恢复到动画执行前的状态 2 basicAnimation.removedOnCompletion = NO; 3 // 设置保存动画状态 4 basicAnimation.fillMode = kCAFillModeForwards;
移除根据key值移除动画:
1 - (void)removeAnimationForKey:(NSString *)key;
- 路径动画:
1 // ***********路径动画*********** 2 // 第一步:创建动画对象 3 CABasicAnimation *basicAnimation = [CABasicAnimation animation]; 4 // 第二步:设置动画轨迹,告诉layer层需要执行什么样的动画,设置的内容为CALayer的相关属性 5 basicAnimation.keyPath = @"position"; 6 // 第三部:设置初始位置和最终位置 7 basicAnimation.fromValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)]; 8 basicAnimation.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 200)]; 9 // 第四步:如果要设置动画完成后不回到初始状态,需要实现以下两句代码 10 // 动画执行完毕后不从图层上移除,图形不会恢复到动画执行前的状态 11 basicAnimation.removedOnCompletion = NO; 12 // 设置保存动画状态 13 basicAnimation.fillMode = kCAFillModeForwards; 14 // 第四步:设置动画时长 15 basicAnimation.duration = 6.0f; 16 // 第五步:将BasicAnimation动画添加到CALayer上 17 [self.testView.layer addAnimation:basicAnimation forKey:@"basic"];
- 旋转动画:
1 // **********旋转效果*********** 2 CABasicAnimation *basic = [CABasicAnimation animation]; 3 basic.keyPath = @"transform"; 4 // 参数1:value值:角度 最大旋转180°,就是会按照你设定的角度得到的效果的最短距离去旋转,如果是360°的倍数就静止不动 5 // 参数2:x 沿x轴旋转 纵向翻转 6 // 参数3:y 沿y轴旋转 横向翻转 7 // 参数4:z 沿z轴旋转 平面旋转 8 basic.toValue = [NSValue valueWithCATransform3D: 9 CATransform3DMakeRotation(M_PI, 0, 0, 1)]; 10 basic.duration = 2.0; 11 [self.testView.layer addAnimation:basic forKey:@"transform"];
- 改变视图内容:
1 CABasicAnimation *contents = [CABasicAnimation animation]; 2 contents.keyPath = @"contents"; 3 contents.toValue = (id)[UIImage imageNamed:@"2.jpg"].CGImage; 4 contents.duration = 1.0f; 5 contents.repeatCount = MAXFLOAT; // 动画无限循环 6 contents.delegate = self;
- 透明效果:
1 // ***********透明************* 2 CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 3 animation.toValue = @0.0f; 4 animation.fromValue = @(self.testView.layer.opacity); 5 animation.duration = 1.0; 6 animation.repeatCount = MAXFLOAT; 7 8 [self.testView.layer addAnimation:animation forKey:@"animateOpacity"];
3.2、CAAnimationGroup
关键属性:
1 - (IBAction)animationGroup:(id)sender { 2 // 平移动画 3 CABasicAnimation *basic1 = [CABasicAnimation animation]; 4 // y轴平移 5 basic1.keyPath = @"transform.translation.y"; 6 basic1.toValue = @(400); 7 // 翻转动画 8 CABasicAnimation *basic2 = [CABasicAnimation animation]; 9 basic2.keyPath = @"transform.rotation.x"; 10 basic2.toValue = @(M_PI); 11 12 // 旋转动画 13 CABasicAnimation *basic3 = [CABasicAnimation animation]; 14 basic3.keyPath = @"cornerRadius"; 15 basic3.toValue = @(30); 16 17 18 // 创建动画组,管理各个动画 19 CAAnimationGroup *group = [CAAnimationGroup animation]; 20 // 数组中存放的是layer层的动画 21 group.animations = @[basic1, basic2, basic3]; 22 // 设置动画时长 23 group.duration = 2.0f; 24 // 添加动画到layer层 25 [self.testView.layer addAnimation:group forKey:@"group"]; 26 }
3.3、CASpringAnimation弹簧动画
关键属性:
1 - (IBAction)springAnimation:(id)sender { 2 CASpringAnimation *springAnimation = [CASpringAnimation animation]; 3 4 springAnimation.keyPath = @"transform.scale"; 5 springAnimation.fromValue = @1; 6 springAnimation.toValue = @0.25; 7 springAnimation.duration = 3.0f; 8 9 [self.testView.layer addAnimation:springAnimation forKey:@"spring"]; 10 }
总结:
- 动画分为两种属性动画和过渡动画。
- UIView层动画的实现分为两种:begin/commit和block。
- Layer层动画分为三种:CAPropertyAnimation、CATransion、CAAnimationGroup。