UIView动画
UIView的属性
transform
view.transform 和 view.layer.transform的区别:
- view.transform:二维,
CGAffineTransform transform
。 - view.layer.transform:3D,
CATransform3D transform
。
- view.transform:二维,
CGAffineTransform:
1
2
3
4
5
6
7
8
9
10
11//还原
CGAffineTransformIdentity
//位移仿射(CGFloat tx,CGFloat ty)
CGAffineTransformMakeTranslation
CGAffineTransformTranslate
//旋转仿射(CGFloat angle)
CGAffineTransformMakeRotation
CGAffineTransformRotate
//缩放仿射(CGFloat sx, CGFloat sy)
CGAffineTransformMakeScale
CGAffineTransformScaleCATransform3D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//还原
CATransform3DIdentity
//位移3D仿射(CGFloat tx, CGFloat ty, CGFloat tz)
CATransform3DMakeTranslation
CATransform3DTranslation
//旋转3D仿射(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeRotation
CATransform3DRotation
//缩放3D仿射(CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
CATransform3DMakeScale
CATransform3DScale
//叠加3D仿射效果
CATransform3DConcat(CATransform3D a, CATransform3D b)
//仿射基础3D方法,可以直接做效果叠加
CGAffineTransformMake (sx,shx,shy,sy,tx,ty)
//检查是否有做过仿射3D效果(CATransform3D t)
CATransform3DIsIdentity(transform)
//检查2个3D仿射效果是否相同
CATransform3DEqualToTransform(transform1,transform2)
//3D仿射效果反转(反效果,比如原来扩大,就变成缩小)
CATransform3DInvert(transform)CGAffineTransform与CGTransform3D的转换
1
2
3
4
5
6//将CGAffinrTransform转化为CATransform3D
CATransform3D CATransform3DMakeAffineTransform (CGAffineTransform m);
//将CATransform3D转换为CGAffineTransform
CGAffineTransform CATransform3DGetAffineTransform (CATransform3D t);
//判断一个CATransform3D是否可以转换为CAAffineTransform
CATransform3DIsAffine (CATransform3D t);使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//view.transform
self.redView.transform = CGAffineTransformIdentity;
[UIView animateWithDuration:1.0f animations:^{
self.redView.transform = CGAffineTransformMakeScale(2.0f, 2.0f);
}];
//view.layer.transform
self.redView.layer.transform = CATransform3DIdentity;
[UIView animateWithDuration:1.0f animations:^{
self.redView.layer.transform = CATransform3DMakeScale(2.0, 2.0, 1.0);
}];
//view.layer.transform
CABasicAnimation *transformAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
transformAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.0, 2.0, 1.0)];
transformAnimation.beginTime = CACurrentMediaTime();
transformAnimation.duration = 1.0f;
transformAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[self.redView.layer addAnimation:transformAnimation forKey:@"transformAnimation"];
UIView动画的实现方式
begin-commit
1 | [UIView beginAnimations:nil context:nil]; |
Block
1 | /* |
- 过渡动画,主要用于UIView进入或者离开视图
1
2
3
4
5[UIView transitionWithView:self.view duration:2.f options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{
//动画效果代码
} completion:^(BOOL finished) {
//动画完成代码
}];
Spring Animation API
1 | [UIView animateWithDuration:(NSTimeInterval)//动画持续时间 |
keyframes动画
关键帧动画,支持属性关键帧,不支持路径关键帧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24/*
UIViewAnimationOptionLayoutSubviews //进行动画时布局子控件
UIViewAnimationOptionAllowUserInteraction //进行动画时允许用户交互
UIViewAnimationOptionBeginFromCurrentState //从当前状态开始动画
UIViewAnimationOptionRepeat //无限重复执行动画
UIViewAnimationOptionAutoreverse //执行动画回路
UIViewAnimationOptionOverrideInheritedDuration //忽略嵌套动画的执行时间设置
UIViewAnimationOptionOverrideInheritedOptions //不继承父动画设置
UIViewKeyframeAnimationOptionCalculationModeLinear //运算模式 :连续
UIViewKeyframeAnimationOptionCalculationModeDiscrete //运算模式 :离散
UIViewKeyframeAnimationOptionCalculationModePaced //运算模式 :均匀执行
UIViewKeyframeAnimationOptionCalculationModeCubic //运算模式 :平滑
UIViewKeyframeAnimationOptionCalculationModeCubicPaced //运算模式 :平滑均匀
*/
[UIView animateKeyframesWithDuration:(NSTimeInterval)//动画持续时间
delay:(NSTimeInterval)//动画延迟执行的时间
options:(UIViewKeyframeAnimationOptions)//动画的过渡效果
animations:^{
//执行的关键帧动画
}
completion:^(BOOL finished) {
//动画执行提交后的操作
}];增加关键帧
1
2
3
4
5[UIView addKeyframeWithRelativeStartTime:(double)//动画开始的时间(占总时间的比例)
relativeDuration:(double) //动画持续时间(占总时间的比例)
animations:^{
//执行的动画
}];
核心动画(Core Animation)
CALayer
CALayer的属性
- bounds
- position:设置CALayer在父层中的位置,是以父层的左上角为坐标原点
- anchorPoint:定位点,决定了CALayer身上的哪个点会在position属性所指的位置,x,y的取值范围是0~1。默认值:(0.5,0.5),所以默认CALayer的中点会在position所指定的位置上。
- RefbackgroundColor(CGColorRef)
- transform(CGTransform3D)
- borderColor(CGColorRef)
- borderWidth
- cornerRadius
- content(id) //可以给UIView设置背景图片,CGImage格式
1 | // 跨框架赋值需要进行桥接 |
隐式动画
- 每个UIView都默认关联着一个CALayer,这个Layer就是RootLayer。所有手动创建的的非RootLayer都存在着隐式动画。
- 可动画属性:对非RootLayer的部分属性进行修改,默认会自动产生一些动画效果,这些属性称为可动画属性。常见的可动画属性:
- bounds:缩放动画
- backgroundColor:渐变动画
- position:平移动画
- 事务可以关闭隐式动画(变换仍存在):
1
2
3
4
5
6
7
8
9
10
11[CATransaction begin];
// 关闭隐式动画
[CATransaction setDisableActions:YES];
//动画效果
self.redView.layer.anchorPoint = CGPointMake(0, 0);
[UIView animateWithDuration:3.0 animations:^{
self.redView.transform = CGAffineTransformMakeRotation(M_PI);
} completion:^(BOOL finished) {
}];
[CATransaction commit];
核心动画
核心动画的特点
- 核心动画的执行过程是在后台操作的,不会阻塞主线程
- 核心动画直接作用在CALayer上
- 属于Quartz Core框架的API
- 不支持交互
核心动画的使用步骤
- 初始化一个CAAnimation的对象,并设置一些动画相关属性
- 通过调用CALayer的
addAnimation:forKey:
增加CAAniamtion对象到CALayer中,开始执行动画 - 通过调用CALayer的
removeAnimation:forKey:
停止CALayer的动画
CAAnimation
- CAAnimation是所有动画对象的父类,是抽象类,不可直接使用,应该使用它具体的子类
CAAnimation继承结构
- CAAnimation->CAMediaTiming协议
- CAPropertyAnimation
- CABasicAnimation
- CAKeyframeAnimation
- CAAnimationGroup
- CATransition
- CAPropertyAnimation
- CAAnimation->CAMediaTiming协议
CAAnimation——动画填充模式(fillMode)
要想fillMode有效,最好设置removedOnCompletion = NO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19// 创建动画
CABasicAnimation *anim = [CABasicAnimation animation];;
// 设置动画对象
// keyPath决定了执行怎样的动画,调用layer的哪个属性来执行动画
// position:平移
anim.keyPath = @"position";
// 包装成对象
anim.fromValue = [NSValue valueWithCGPoint:CGPointMake(0, 0)];;
anim.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 300)];
anim.duration = 2.0;
// 让图层保持动画执行完毕后的状态
// 执行完毕以后不要删除动画
anim.removedOnCompletion = NO;
// 保持最新的状态
anim.fillMode = kCAFillModeForwards;
// 添加动画
[self.redView.layer addAnimation:anim forKey:nil];
fillMode属性值:
- kCAFillModeRemoved 默认值,也就是说当动画开始前和动画结束后,动画对layer都没有影响,动画结束后,layer会恢复到之前的状态
- kCAFillModeForwards 当动画结束后,layer会一直保持着动画最后的状态
- kCAFillModeBackwards 在动画开始前,只需要将动画加入了一个layer,layer便立即进入动画的初始状态并等待动画开始。
- kCAFillModeBoth 动画加入后开始之前,layer便处于动画初始状态,动画结束后layer保持动画最后的状态
- CAAnimation——速度控制函数(timingFunction)
CAMediaTimingFunction属性值:- kCAMediaTimingFunctionLinear(线性)
- kCAMediaTimingFunctionEaseIn(渐进)
- kCAMediaTimingFunctionEaseOut(渐出)
- kCAMediaTimingFunctionEaseInEaseOut(渐进渐出)
1 | //设置动画的执行节奏 |
CAAnimation——动画代理方法(delegate)
1
2
3//CAAnimationDelegate
- (void)animationDidStart:(CAAnimation *)anim;
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag;CALayer上动画的暂停和恢复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
static NSInteger count = 0;
if (count++%2 == 0) {
[self pauseLayer:self.redView.layer];
}else{
[self resumeLayer:self.redView.layer];
}
}
//停止
-(void)pauseLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
//让CALayer的时间停止走动
layer.speed = 0.0;
//让CALayer的时间停留在pausedTime这个时刻
layer.timeOffset = pausedTime;
}
//恢复
-(void)resumeLayer:(CALayer*)layer
{
CFTimeInterval pausedTime = layer.timeOffset;
//1. 让CALayer的时间继续行走
layer.speed = 1.0;
//2. 取消上次记录的停留时刻
layer.timeOffset = 0.0;
//3. 取消上次设置的时间
layer.beginTime = 0.0;
//4. 计算暂停的时间(这里也可以用CACurrentMediaTime()-pausedTime)
CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
//5. 设置相对于父坐标系的开始时间(往后退timeSincePause)
layer.beginTime = timeSincePause;
}
CAPropertyAnimation 抽象类
- 通过指定CALayer的一个属性名称为keyPath(NSString类型),并且对CALayer的这个属性值进行修改,达到响应动画效果。
keyPath是CALayer的可动画属性
CABasicAnimation
1 | //创建动画对象 |
CAKeyframeAnimation 关键帧动画
- 与CABasicAnimation的区别:
- CABasicAnimation:只能从fromValue变到toValue(可看做只有2个关键帧的CAKeyframeAnimation)
- CAKeyframeAnimation:会使用NSArray保存这些数值
1 | // 创建动画 |
- 根据路径创建动画
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 创建动画
CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
anim.keyPath = @"position";
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeForwards;
anim.duration = 2.0;
// 创建一个路径
CGMutablePathRef path = CGPathCreateMutable();
// 路径的范围
CGPathAddEllipseInRect(path, NULL, CGRectMake(100, 100, 200, 200));
// 添加路径
anim.path = path;
// 释放路径(带Create的函数创建的对象都需要手动释放,否则会内存泄露)
CGPathRelease(path);
// 添加到View的layer
[self.redView.layer addAnimation:anim forKey:nil];
CAAnimationGroup 动画组
1 | CAAnimationGroup *group = [CAAnimationGroup animation]; |
- 播放gif图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSArray *imageArray = [self getImageArrayWithGIFNameWit:@"aisi"];
self.imageView.animationImages = imageArray;
self.imageView.animationDuration = 3;
self.imageView.animationRepeatCount = MAXFLOAT;
[self.imageView startAnimating];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[_imageView stopAnimating];
});
}
- (NSArray<UIImage *> *)getImageArrayWithGIFNameWit:(NSString *)imageName {
NSMutableArray *imageArray = [NSMutableArray array];
NSString *path = [[NSBundle mainBundle] pathForResource:imageName ofType:@"gif"];
NSData *data = [NSData dataWithContentsOfFile:path];
if (!data) {
NSLog(@"图片不存在!");
return nil;
}
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
size_t count = CGImageSourceGetCount(source);
if (count <= 1) {
[imageArray addObject:[[UIImage alloc] initWithData:data]];
}else {
for (size_t i = 0; i < count; i++) {
CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL);
[imageArray addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]];
CGImageRelease(image);
}
}
CFRelease(source);
return imageArray;
}
CATransition 转场动画
作用对象是父视图,过渡效果体现在父视图上
- 创建转场动画
- 创建动画对象:[CATransition animation];
- 设置动画属性值
- 添加到需要转场动画的图层上: [ layer addAimation:animation forKer:nil];
- 动画属性
- type
- subtype
- startProgress
- endProgress
1 | /* |
使用UIView实现转场动画
单个视图的过渡效果
1
2
3
4
5
6
7
8
9[UIView transitionWithView:(nonnull UIView *)
duration:(NSTimeInterval)
options:(UIViewAnimationOptions)
animations:^{
//执行的动画
}
completion:^(BOOL finished) {
//动画执行提交后的操作
}];双视图的过渡效果
1
2
3
4
5
6
7[UIView transitionFromView:(nonnull UIView *) toView:(nonnull UIView *) duration:(NSTimeInterval) options:(UIViewAnimationOptions) completion:^(BOOL finished) {
//动画执行提交后的操作
}];
//相当于
//[fromView.superview addSubview:toView];
//[fromView removeFromSuperview];