第六篇:UIView block动画
在开始学习Core Animation提供的layer的隐式动画和layer的显式动画之前,我们先来总结一下UIView block动画,因为:
- 在实际开发中我们用的最多的还是view,而不是layer,所以更多情况下如果我们要做动画的话,用的还是UIView block动画,而不是layer的隐式动画和显示动画;
- 这里总结一下,可以方便我们在后面两篇学习layer的隐式动画和显式动画时作对比,以期加深对动画的理解。
目录
一、UIView可动画属性列表
二、什么是UIView block动画?
1、UIView block动画的定义、本质及能做什么动画
2、UIView block动画的分类
(1)UIView block基础动画(UIView block属性动画的一种)
(2)UIView block关键帧动画(UIView block属性动画的一种)
(3)UIView block过渡动画
三、如何使用UIView block动画?(应用举例)
1、UIView block基础动画举例
2、UIView block关键帧动画举例
3、UIView block过渡动画举例
一、UIView可动画属性列表
最普通的属性 | 说明 |
---|---|
backgroundColor | -- |
frame | 改位置和大小,一般使用transform的平移和缩放来代替 |
bounds | 改大小,一般使用transform的缩放来代替 |
center | 改位置,一般使用transform的平移来代替 |
显隐性属性 | 说明 |
---|---|
hidden | 注意这个属性不支持动画,最简单的可以通过alpha或背景色来代替实现 |
alpha | -- |
仿射变换属性 | 说明 |
---|---|
transform | 可用来做view的平移、缩放、旋转动画 |
二、什么是UIView block动画?
1、UIView block动画的定义、本质及能做什么动画
-
定义:UIView block动画就是用来在view层做动画的一种动画机制
-
本质:UIView block动画的本质就是对layer的隐式动画或显式动画做了一层封装,提供简洁的Api,方便我们开发者使用。具体来说UIView block基础动画是对layer的隐式动画做了封装(因为它们同样可以设置过渡效果/图层行为,显示动画的基础动画不能设置图层行为,当然显式动画的过渡动画也可以作用于可动画属性,但是后面讲到隐式动画应该会知道UIView block基础动画是对layer的隐式动画做了封装),UIView block关键帧动画是对layer的显示动画的关键帧动画做了封装,UIView block过渡动画是对layer的显示动画的过渡动画做了封装。
-
能做什么动画:
-
下面我们会提到UIView block动画可分为UIView block属性动画和UIView block过渡动画,而UIView block属性动画又可分为UIView block基础动画和UIView block关键帧动画。
-
UIView block属性动画能做什么动画:那么从UIView的可动画属性列表我们可以看出,UIView block属性动画可以用来对view做背景色变化的动画、view显隐性变化的动画以及view的平移、缩放和旋转的仿射变换动画这三种场景下的动画,其中执行一次UIView block基础动画只能改变一个属性值一次,执行一次UIView block关键帧动画可以设置多个关键帧所以能改变一个属性值多次。
-
UIView block过渡动画能做什么动画:UIView block属性动画只能对UIView的可动画属性做动画,但是如果我们现在想要对view的非动画属性改变时(如label的文本,imageView的图片等)做动画,甚至是对view的某些行为(如view的添加和移除,两个view之间切换)做动画,那就只能使用过渡动画了。
-
- 就此我们也就知道了为什么要引入UIView block动画:
- 第一、当然就是UIView block动画是作用于view层,对layer的隐式动画或显式动画做了一层封装,提供简洁的Api,方便我们开发者使用;
- 第二、UIView block属性动画可以帮助我们在改变view的可动画属性时能做动画效果。如果看到后面一篇隐式动画,我们会知道在改变layer的可动画属性时,即便我们什么都不做直接修改layer的属性值,这个改变的过程也会默认有一个动画,它就是隐式动画;但是当我们在改变view的可动画属性时,是没有隐式动画的,如果我们什么都不做,属性就会直接跳变到新值,所以为了达到改变view的属性时能有动画,我们就得使用UIView block动画来实现了。
- 第三、UIView block过渡动画可以帮助我们在改变view的不可变属性或者对view做某些行为能做动画。
2、UIView block动画的分类
UIView block动画可分为UIView block属性动画和UIView block过渡动画,而UIView block属性动画又可分为UIView block基础动画和UIView block关键帧动画,接下来我们将分别介绍UIView block基础动画、UIView block关键帧动画和UIView block过渡动画。
(1)UIView block基础动画
①什么是UIView block基础动画?
UIView block基础动画是UIView block属性动画的一种,它用来对view的可动画属性做动画,但是执行一次UIView block基础动画只能改变一个属性值一次,因为我们是一次性把属性值直接设置为目标值的(如果要想改变多次属性的值,可以在动画结束后再开始一个基础动画再改一次属性值,如此循环,但有一个更简单的办法就是使用UIView block关键帧动画,后面会说到)它主要分下面四种:
- 最简洁的block基础动画
[UIView animateWithDuration:// 动画时长
animations:^{
// 要改变的属性
}];
- 带动画完成回调的block基础动画
[UIView animateWithDuration:// 动画时长
animations:^{
// 要改变的属性
} completion:^(BOOL finished) {
// 动画完成的回调
}];
- 可设置延时和自定义动画过渡效果的block基础动画
[UIView animateWithDuration:// 动画时长
delay:// 延时多长时间后开始执行动画
options:// 可自定义动画的过渡效果,来替换掉系统默认的平滑过渡效果
animations:^{
// 要改变的属性
} completion:^(BOOL finished) {
// 动画完成的回调
}];
UIView block基础动画自定义过渡效果(UIViewAnimationOptions)枚举值如下:
-
一般就设置下过渡动画效果和过渡动画时间曲线就可以了;
-
如果和后面layer显式动画的过渡动画的type和subType对比一下,会发现这里的过渡动画效果是把layer显式动画的过渡动画的type和subType组合起来了,而且这里的过渡动画效果要比layer显式动画的过渡动画的效果少得多,只有淡入淡出、正面背面二维翻转、翻页效果三种而已。
UIViewAnimationOptionTransitionNone// 过渡动画效果:不使用过渡动画
UIViewAnimationOptionTransitionCrossDissolve//过渡动画效果:淡入淡出效果,和显示动画的过渡动画的“fade”一样
UIViewAnimationOptionTransitionFlipFromTop// 过渡动画效果:正面和背面的二维翻转效果,从上向下翻转
UIViewAnimationOptionTransitionFlipFromLeft// 过渡动画效果:正面和背面的二维翻转效果,从左向右翻转
UIViewAnimationOptionTransitionFlipFromBottom// 过渡动画效果:正面和背面的二维翻转效果,从下向上翻转
UIViewAnimationOptionTransitionFlipFromRight//过渡动画效果:正面和背面的二维翻转效果,从右向左翻转
UIViewAnimationOptionTransitionCurlUp// 过渡动画效果:翻页效果,从下往上翻页
UIViewAnimationOptionTransitionCurlDown// 过渡动画效果:翻页效果,从上往下翻页
UIViewAnimationOptionCurveEaseInOut// 过渡动画的缓冲曲线:动画慢进,逐渐加快,逐渐减慢,慢出(默认值)
UIViewAnimationOptionCurveEaseIn// 过渡动画的缓冲曲线:动画慢进,逐渐加快
UIViewAnimationOptionCurveEaseOut// 过渡动画的缓冲曲线:动画逐渐减慢,慢出
UIViewAnimationOptionCurveLinear// 过渡动画的缓冲曲线:动画匀速
UIViewAnimationOptionRepeat// 重复执行动画
UIViewAnimationOptionAllowUserInteraction// 执行动画期间,开启view的用户交互
UIViewAnimationOptionAutoreverse// 执行动画回路
UIViewAnimationOptionLayoutSubviews// 执行动画时布局子控件
UIViewAnimationOptionAllowAnimatedContent// 执行动画时重绘视图
UIViewAnimationOptionBeginFromCurrentState// 从当前状态开始执行动画
UIViewAnimationOptionShowHideTransitionViews// 显示视图时显示或隐藏而不是移除或添加
UIViewAnimationOptionOverrideInheritedOptions// 不继承父动画设置
UIViewAnimationOptionOverrideInheritedCurve// 忽略嵌套动画的曲线设置
UIViewAnimationOptionOverrideInheritedDuration// 忽略嵌套动画的执行时间设置
- Spring动画:就是指在改变属性的时候,属性值会在目标值附近摆动,类似弹簧那种的弹性动画
[UIView animateWithDuration:// 动画时长
delay:// 延时多长时间后开始执行动画
usingSpringWithDamping:// 弹性效果的阻尼:范围0~1,数值越小弹性效果越明显,震得越久才能停下来
initialSpringVelocity:// 弹性效果的初始速度:数值越大开始弹性动画时初始速度越快
options:// 可自定义动画的过渡效果,来替换掉系统默认的平滑过渡效果
animations:^{
// 要改变的属性
} completion:^(BOOL finished) {
// 动画完成的回调
}];
②如何使用UIView block基础动画?
我们只需要在UIView block基础动画的animations
block里直接把可动画属性改变为目标值就可以了。
(2)UIView block关键帧动画
①什么是UIView block关键帧动画?
上面说到了UIView block基础动画是UIView block属性动画的一种,而此处的UIView block关键帧动画也是UIView block属性动画的一种,它也是用来对view的可动画属性做动画的,只不过效果可能在某些场景下比基础动画要方便或者丰富一些,但是执行一次UIView block关键帧动画可以设置多个关键帧所以能改变一个属性值多次,而不是一次性把属性值设置目标值。
需要注意的是:UIView block关键帧动画设置关键帧只能通过增加关键帧方法来设置,相当于layer显示动画的关键帧动画的数组关键帧法,这个是不支持路径关键帧法的。
- UIView block关键帧动画
[UIView animateKeyframesWithDuration:// 动画时长
delay:// 延时多长时间后开始执行动画
options:// 可自定义动画的过渡效果,来替换掉系统默认的平滑过渡效果
animations:^{
// 添加关键帧
} completion:^(BOOL finished) {
// 动画完成的回调
}];
UIView block关键帧自定义过渡效果(UIViewKeyframeAnimationOptions)枚举值如下:
- 一般就设置下过渡动画的运算模式就可以了,或者直接采取默认就可以了。
UIViewKeyframeAnimationOptionCalculationModeLinear// 运算模式:连续,默认
UIViewKeyframeAnimationOptionCalculationModeDiscrete// 运算模式:离散
UIViewKeyframeAnimationOptionCalculationModePaced// 运算模式:均匀执行
UIViewKeyframeAnimationOptionCalculationModeCubic// 运算模式:平滑
UIViewKeyframeAnimationOptionCalculationModeCubicPaced// 运算模式:平滑均匀
UIViewKeyframeAnimationOptionRepeat = UIViewAnimationOptionRepeat// 重复执行动画
UIViewKeyframeAnimationOptionAllowUserInteraction = UIViewAnimationOptionAllowUserInteraction// 执行动画期间,开启view的用户交互
UIViewKeyframeAnimationOptionAutoreverse = UIViewAnimationOptionAutoreverse// 执行动画回路
UIViewKeyframeAnimationOptionLayoutSubviews = UIViewAnimationOptionLayoutSubviews// 执行动画时布局子控件
UIViewKeyframeAnimationOptionBeginFromCurrentState = UIViewAnimationOptionBeginFromCurrentState// 从当前状态开始执行动画
UIViewKeyframeAnimationOptionOverrideInheritedOptions = UIViewAnimationOptionOverrideInheritedOptions// 不继承父动画设置
UIViewKeyframeAnimationOptionOverrideInheritedDuration = UIViewAnimationOptionOverrideInheritedDuration// 忽略嵌套动画的执行时间设置
- 增加关键帧的方法
[UIView addKeyframeWithRelativeStartTime:// 这一帧动画开始的时间点(占总时间的比例)
relativeDuration:// 这一帧动画的动画时长(占总时间的比例)
animations:^{
// 要改变的属性
}];
②如何使用UIView block关键帧动画?
我们只需要在UIView block关键帧动画的animationsblock
里直接增加关键帧就可以了,再在增加关键帧方法的animationsblock
里把可动画属性改变为目标值就可以了。
(3)UIView block过渡动画
①什么是UIView block过渡动画?
前面我们学习了UIView block基础动画和UIView block关键帧动画,但我们知道它俩其实都是UIView block属性动画,即只能用来对view的可动画属性做动画。那么如果我们现在想要对view的非动画属性改变时(如label的文本,imageView的图片等)做动画,甚至是对view的某些行为(如view的添加和移除,两个view之间切换)做动画,那就只能使用过渡动画了。
同时我们也可以看到,上面UIView block基础动画和UIView block关键帧动画的某些方法里也提供了过渡效果那个配置,也就是说过渡动画也是可以作用于可动画属性的,但是还可以做可动画属性之外的很多效果。
过渡动画的过渡效果可参见UIView block基础动画的过渡效果,是一模一样的。
- 给单个视图的不可动画属性或视图行为添加过渡动画
[UIView transitionWithView:// 要做动画的视图
duration:// 动画时长
options:// 过渡动画效果
animations:^{
// 要改变的不可动画属性或图层行为
} completion:^(BOOL finished) {
// 动画完成的回调
}];
- 给两个视图切换时添加过渡动画
注意:
- 这个方法的过渡效果是体现在fromView和toView的父视图上的
- 这个方法不需要提前把fromView和toView都添在父视图上,只需要先添加fromView就可以了
- 这个方法在动画过程中,会自动把fromView会从父视图中移除,并把toView添加到父视图上
[UIView transitionFromView:// 旧视图
toView:// 新视图
duration:// 动画时长
options:// 动画过渡效果
completion:^(BOOL finished) {
// 动画完成时的回调
}];
②如何使用UIView block过渡动画?
我们只需要根据场景是改变单个视图的不可动画属性或视图行为要添加过渡动画还是给两个视图切换时添加过渡动画选择相应的方法就可以了。
三、UIView的block动画应用举例
1、UIView block基础动画
- 让一条弹幕从右往左飘过去
(清单1.1)
//
// ViewController.m
// CoreAnimation
//
// Created by 意一yiyi on 2017/11/13.
// Copyright © 2017年 意一yiyi. All rights reserved.
//
#import "ViewController.h"
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (strong, nonatomic) UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.label = [[UILabel alloc] init];
self.label.backgroundColor = [UIColor magentaColor];
self.label.frame = CGRectMake(kScreenWidth, 100, kScreenWidth, 30);
self.label.text = @"嘿Siri,你在哪儿?";
[self.view addSubview:self.label];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:5 animations:^{
self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
- 漂完之后,我们改变下弹幕内容
(清单1.2)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:5 animations:^{
self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
} completion:^(BOOL finished) {
self.label.text = @"你在哪儿,我就在哪儿!";
}];
}
- 我们可以让弹幕匀速地飘过,而不是默认的easyInEasyOut
(清单1.3)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:3 delay:0 options:(UIViewAnimationOptionCurveLinear) animations:^{
self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
} completion:^(BOOL finished) {
self.label.text = @"你在哪儿,我就在哪儿!";
}];
}
- 让弹幕弹一弹
(清单1.4)
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView animateWithDuration:3 delay:0 usingSpringWithDamping:0.2 initialSpringVelocity:5 options:(UIViewAnimationOptionCurveLinear) animations:^{
self.label.transform = CGAffineTransformMakeTranslation(-kScreenWidth, 0);
} completion:^(BOOL finished) {
self.label.text = @"你在哪儿,我就在哪儿!";
}];
}
1.gif
2、UIView block关键帧动画
类似FaceBook登录界面,登录失败那种输入框抖动的效果。要是使用基础动画的话,可能就得平移一次,再开一个基础动画再平移一次,得开好几个基础动画,关键帧动画的话就开一个动画就可以了,添关键帧就行了。
(清单1.5)
//
// ViewController.m
// CoreAnimation
//
// Created by 意一yiyi on 2017/11/13.
// Copyright © 2017年 意一yiyi. All rights reserved.
//
#import "ViewController.h"
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (strong, nonatomic) UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.label = [[UILabel alloc] init];
self.label.backgroundColor = [UIColor cyanColor];
self.label.frame = CGRectMake(0, 100, kScreenWidth, 30);
self.label.text = @"请登录";
[self.view addSubview:self.label];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.label.text = @"登录失败";
[UIView animateKeyframesWithDuration:0.5 delay:0 options:(UIViewKeyframeAnimationOptionCalculationModePaced) animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1/4.0 animations:^{
self.label.transform = CGAffineTransformMakeTranslation(10, 0);
}];
[UIView addKeyframeWithRelativeStartTime:1/4.0 relativeDuration:1/4.0 animations:^{
self.label.transform = CGAffineTransformMakeTranslation(-10, 0);
}];
[UIView addKeyframeWithRelativeStartTime:2/4.0 relativeDuration:1/4.0 animations:^{
self.label.transform = CGAffineTransformMakeTranslation(10, 0);
}];
[UIView addKeyframeWithRelativeStartTime:3/4.0 relativeDuration:1/4.0 animations:^{
self.label.transform = CGAffineTransformMakeTranslation(0, 0);
}];
} completion:^(BOOL finished) {
NSLog(@"动画结束了");
}];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
1.gif
3、UIView block过渡动画
(1)给单个视图的不可动画属性或视图行为添加过渡动画
- 切换imageView的图片和label的文本
(清单1.6)
//
// ViewController.m
// CoreAnimation
//
// Created by 意一yiyi on 2017/11/13.
// Copyright © 2017年 意一yiyi. All rights reserved.
//
#import "ViewController.h"
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (strong, nonatomic) UIImageView *imageView;
@property (strong, nonatomic) UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.imageView = [[UIImageView alloc] init];
self.imageView.frame = CGRectMake(0, 64, kScreenWidth, kScreenWidth);
self.imageView.image = [UIImage imageNamed:@"0.jpg"];
[self.view addSubview:self.imageView];
self.label = [[UILabel alloc] init];
self.label.frame = CGRectMake(0, kScreenWidth + 100, kScreenWidth, 30);
self.label.text = @"奥黛丽赫本";
self.label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:self.label];
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSInteger num = arc4random()%7;
// 改变imageView的图片,淡入淡出效果
[UIView transitionWithView:self.imageView duration:3 options:(UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveLinear) animations:^{
self.imageView.image = [UIImage imageNamed:[NSString stringWithFormat:@"%ld.jpg", num]];
} completion:nil];
// 改变label的文本,二维翻转效果
[UIView transitionWithView:self.label duration:3 options:(UIViewAnimationOptionTransitionFlipFromLeft | UIViewAnimationOptionCurveLinear) animations:^{
switch (num) {
case 0:
self.label.text = @"奥黛丽·赫本";
break;
case 1:
self.label.text = @"苏菲·玛索";
break;
case 2:
self.label.text = @"泰勒·斯威夫特";
break;
case 3:
self.label.text = @"安妮·海瑟薇";
break;
case 4:
self.label.text = @"娜塔丽·波特曼";
break;
case 5:
self.label.text = @"凯拉·奈特利";
break;
case 6:
self.label.text = @"杰西卡·阿尔芭";
break;
}
} completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
1.gif
- 淡入淡出的效果添加view
(清单1.7)
//
// ViewController.m
// CoreAnimation
//
// Created by 意一yiyi on 2017/11/13.
// Copyright © 2017年 意一yiyi. All rights reserved.
//
#import "ViewController.h"
#define kScreenWidth [UIScreen mainScreen].bounds.size.width
#define kScreenHeight [UIScreen mainScreen].bounds.size.height
@interface ViewController ()
@property (strong, nonatomic) UIImageView *imageView;
@property (strong, nonatomic) UILabel *label;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.imageView = [[UIImageView alloc] init];
self.imageView.frame = CGRectMake(0, 64, kScreenWidth, kScreenWidth);
self.imageView.image = [UIImage imageNamed:@"0.jpg"];
self.label = [[UILabel alloc] init];
self.label.frame = CGRectMake(0, kScreenWidth + 100, kScreenWidth, 30);
self.label.text = @"奥黛丽赫本";
self.label.textAlignment = NSTextAlignmentCenter;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[UIView transitionWithView:self.view duration:3 options:(UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionCurveLinear) animations:^{
[self.view addSubview:self.imageView];
[self.view addSubview:self.label];
} completion:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
1.gif
(2)给两个视图切换时添加过渡动画
- 例如切换登录和注册视图(当然这个也可以UIViewController的方法来替换,有同样的效果)