共计 12089 个字符,预计需要花费 31 分钟才能阅读完成。
前言
以前要做动画方面相关的功能时都是去百度,想着自己也总结下,方便自己记忆和查找,更加深自己对这方面的理解
iOS 图形分层
日常开发 UIKIt 层和 Core Animation 层的动画基本可以实现绝大多数需求,并且层级越高 API 的封装程度越高,也越简洁。本文主要讲解 View Animation 和 Core Animation。
UIKit 层
UIView Animation
我们来看看通过 UIView Animation 都可以实现那些动画
大小动画(frame 改变)
#pragma mark ——————— 大小动画,frame 改变
– (void)initSizeAnimation {
CGRect origin = self.showImage.frame;
CGRect terminal = CGRectMake(SCREEN_W/2-100, SCREEN_H/2-100, 200, 200);
[UIView animateWithDuration:1 animations:^{
self.showImage.frame = terminal;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 animations:^{
self.showImage.frame = origin;
}];
}];
}
拉伸动画 bounds 改变
#pragma mark —————— 拉伸动画 bounds 改变
– (void)initBoundsAnimation {
CGRect origin = self.showImage.bounds;
// 拉伸动画基于 view 的 bound 改变,只改变宽高,
CGRect terminal = CGRectMake(0, 0, 200, 150);
[UIView animateWithDuration:1 animations:^{
self.showImage.bounds = terminal;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 animations:^{
self.showImage.bounds = origin;
}];
}];
}
中心位置动画,改变 center
#pragma mark —————- 中心位置动画,改变 center
– (void)initCenterAnimation {
CGPoint origin = self.showImage.center;
CGPoint terminal = CGPointMake(self.showImage.center.x, self.showImage.center.y-100);
[UIView animateWithDuration:1 animations:^{
self.showImage.center = terminal;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 animations:^{
self.showImage.center = origin;
}];
}];
}
旋转动画,改变 transform
#pragma mark —————- 旋转动画,改变 transform
– (void)initTransformAnimation {
CGAffineTransform origin = self.showImage.transform;
[UIView animateWithDuration:2 animations:^{
// self.showImage.transform = CGAffineTransformMakeScale(0.6, 0.6);// 缩放
// self.showImage.transform = CGAffineTransformMakeTranslation(60, -60);// 偏移
self.showImage.transform = CGAffineTransformMakeRotation(4.0f);// 旋转
} completion:^(BOOL finished) {
[UIView animateWithDuration:2 animations:^{
self.showImage.transform = origin;
}];
}];
}
透明度动画 改变 alpha
#pragma mark —————- 透明度动画 改变 alpha
– (void)initAlphaAnimation {
[UIView animateWithDuration:2 animations:^{
self.showImage.alpha = 0.3;
} completion:^(BOOL finished) {
[UIView animateWithDuration:2 animations:^{
self.showImage.alpha = 1;
}];
}];
}
转场动画 transition
#pragma mark —————- 转场动画 transition
– (void)initTransitionAnimation {
[UIView transitionWithView:self.showImage duration:2.0 options:UIViewAnimationOptionTransitionFlipFromTop animations:^{
} completion:^(BOOL finished) {
[UIView transitionWithView:self.showImage duration:2 options:UIViewAnimationOptionTransitionFlipFromBottom animations:^{
} completion:^(BOOL finished) {
}];
}];
}
spring 动画(弹簧效果)(ios7 以上)
#pragma mark —————-spring 动画(弹簧效果)
– (void)initSpringAnimation {
CGRect origin = self.showImage.frame;
CGRect terminal = CGRectMake(origin.origin.x+50, origin.origin.y, 150, 150);
[UIView animateWithDuration:1 delay:0 usingSpringWithDamping:0.5 initialSpringVelocity:4 options:UIViewAnimationOptionCurveLinear animations:^{
self.showImage.frame = terminal;
} completion:^(BOOL finished) {
[UIView animateWithDuration:1 delay:1 usingSpringWithDamping:0.5 initialSpringVelocity:4 options:UIViewAnimationOptionCurveLinear animations:^{
self.showImage.frame = origin;
} completion:^(BOOL finished) {
}];
}];
}
背景颜色动画
#pragma mark —————- 背景颜色动画 改变 background
– (void)initBackgroundAnimation {
self.showImage.image = [UIImage imageNamed:@”example1″];
[UIView animateKeyframesWithDuration:6.0 delay:0.f options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{
[UIView addKeyframeWithRelativeStartTime:0.f relativeDuration:1.0 / 4 animations:^{
self.showImage.backgroundColor = [UIColor redColor];
}];
[UIView addKeyframeWithRelativeStartTime:1.0 / 4 relativeDuration:1.0 / 4 animations:^{
self.showImage.backgroundColor = [UIColor greenColor];
}];
[UIView addKeyframeWithRelativeStartTime:2.0 / 4 relativeDuration:1.0 / 4 animations:^{
self.showImage.backgroundColor = [UIColor yellowColor];
}];
[UIView addKeyframeWithRelativeStartTime:2.0 / 4 relativeDuration:1.0 / 4 animations:^{
self.showImage.backgroundColor = [UIColor greenColor];
}];
[UIView addKeyframeWithRelativeStartTime:1.0 / 4 relativeDuration:1.0 / 4 animations:^{
self.showImage.backgroundColor = [UIColor whiteColor];
}];
} completion:^(BOOL finished) {
NSLog(@” 动画结束 ”);
}];
}
UIViewAnimationOptions
UIViewAnimationOptionLayoutSubviews // 进行动画时布局子控件
UIViewAnimationOptionAllowUserInteraction // 进行动画时允许用户交互
UIViewAnimationOptionBeginFromCurrentState // 从当前状态开始动画
UIViewAnimationOptionRepeat // 无限重复执行动画
UIViewAnimationOptionAutoreverse // 执行动画回路
UIViewAnimationOptionOverrideInheritedDuration // 忽略嵌套动画的执行时间设置
UIViewAnimationOptionOverrideInheritedCurve // 忽略嵌套动画的曲线设置
UIViewAnimationOptionAllowAnimatedContent // 转场:进行动画时重绘视图
UIViewAnimationOptionShowHideTransitionViews // 转场:移除(添加和移除图层的)动画效果
UIViewAnimationOptionOverrideInheritedOptions // 不继承父动画设置
UIViewAnimationOptionCurveEaseInOut // 时间曲线,慢进慢出(默认值)
UIViewAnimationOptionCurveEaseIn // 时间曲线,慢进
UIViewAnimationOptionCurveEaseOut // 时间曲线,慢出
UIViewAnimationOptionCurveLinear // 时间曲线,匀速
UIViewAnimationOptionTransitionNone // 转场,不使用动画
UIViewAnimationOptionTransitionFlipFromLeft // 转场,从左向右旋转翻页
UIViewAnimationOptionTransitionFlipFromRight // 转场,从右向左旋转翻页
UIViewAnimationOptionTransitionCurlUp // 转场,下往上卷曲翻页
UIViewAnimationOptionTransitionCurlDown // 转场,从上往下卷曲翻页
UIViewAnimationOptionTransitionCrossDissolve // 转场,交叉消失和出现
UIViewAnimationOptionTransitionFlipFromTop // 转场,从上向下旋转翻页
UIViewAnimationOptionTransitionFlipFromBottom // 转场,从下向上旋转翻页
UIViewKeyframeAnimationOptions
UIViewAnimationOptionLayoutSubviews // 进行动画时布局子控件
UIViewAnimationOptionAllowUserInteraction // 进行动画时允许用户交互
UIViewAnimationOptionBeginFromCurrentState // 从当前状态开始动画
UIViewAnimationOptionRepeat // 无限重复执行动画
UIViewAnimationOptionAutoreverse // 执行动画回路
UIViewAnimationOptionOverrideInheritedDuration // 忽略嵌套动画的执行时间设置
UIViewAnimationOptionOverrideInheritedOptions // 不继承父动画设置
UIViewKeyframeAnimationOptionCalculationModeLinear // 运算模式 : 连续
UIViewKeyframeAnimationOptionCalculationModeDiscrete // 运算模式 : 离散
UIViewKeyframeAnimationOptionCalculationModePaced // 运算模式 : 均匀执行
UIViewKeyframeAnimationOptionCalculationModeCubic // 运算模式 : 平滑
UIViewKeyframeAnimationOptionCalculationModeCubicPaced // 运算模式 : 平滑均匀
总结
UIView 动画主要变化 UIView 自身的属性
一个效果有多种方式实现,通过组合也可以实现比较高级的动画效果
Core Animation
Core Animation 是直接作用在 CALayer 上的,iOS 和 Mac OS 都可以使用,Core Animation 的动画过程都是在后台操作的,不会阻塞主线程。
下面是 Core Animation 所涉及的几个类的继承关系
CAMediaTiming 协议中定义了时间、速度、重复次数等,包含属性:
beginTime:设置延时时间
duration:持续时间
speed:动画速率
timeOffset:动画时间偏移量
repeatCount:动画的重复次数等
repeatDuration:重复时间
autoreverses:结束后是否反过来恢复到初始值
fillMode:当前对象在非对象时间段的初始值
CAAnimation 核心动画基础类,不能直接使用
timingFunction -> 控制动画的节奏。系统提供的包括:
kCAMediaTimingFunctionLinear(匀速)
kCAMediaTimingFunctionEaseIn(慢进快出)
kCAMediaTimingFunctionEaseOut(快进慢出)
kCAMediaTimingFunctionEaseInEaseOut(慢进慢出,中间加速)
kCAMediaTimingFunctionDefault(默认),当然也可通过自定义创建 CAMediaTimingFunction
delegate -> 代理。
emovedOnCompletion -> 是否让图层保持显示动画执行后的状态,默认为 YES,也就是动画执行完毕后从涂层上移除,恢复到执行前的状态,如果设置为 NO,并且设置 fillMode 为 kCAFillModeForwards,则保持动画执行后的状态。
CAPropertyAnimation 属性动画,针对对象的可动画属性进行效果的设置,不可直接使用。
keyPath -> CALayer 的某个属性名,并通过这个属性的值进行修改,达到相应的动画效果。
additive -> 属性动画是否以当前动画效果为基础,默认为 NO。
cumulative -> 指定动画是否为累加效果,默认为 NO。
valueFunction -> 此属性配合 CALayer 的 transform 属性使用。
CABasicAnimation 基础动画,通过 keyPath 对应属性进行控制,需要设置 fromValue 以及 toValue,只能在两个属性间变化。
fromValue -> keyPath 相应属性的初始值。
toValue -> keyPath 相应属性的结束值。
byValue -> 在不设置 toValue 时,toValue = fromValue + byValue,也就是在当前的位置上增加多少。
CASpringAnimation 带有初始速度以及阻尼指数等物理参数的属性动画。
mass -> 小球质量,影响惯性
stiffness -> 弹簧的劲度系数
damping -> 阻尼系数,地面的摩擦力
initialVelocity -> 初始速度,相当于给小球一个初始速度(可正可负,方向不同)
settlingDuration -> 结算时间,根据上述参数计算出的预计时间,相对于你设置的时间,这个时间比较准确。
CAKeyframeAnimation 关键帧动画,同样通过 keyPath 对应属性进行控制,但它可以通过 values 或者 path 进行多个阶段的控制
values -> 关键帧组成的数组,动画会依次显示其中的每一帧
path -> 关键帧路径,动画进行的要素,优先级比 values 高,但是只对 CALayer 的 anchorPoint 和 position 起作用
keyTimes -> 每一帧对应的时间,如果不设置,则各关键帧平分设定时间
timingFunctions -> 每一帧对应的动画节奏
calculationMode -> 动画的计算模式,系统提供了对应的几种模式
tensionValues -> 动画张力控制
continuityValues -> 动画连续性控制
biasValues -> 动画偏差率控制
rotationMode -> 动画沿路径旋转方式,系统提供了两种模式。
CATransition 转场动画,系统提供了很多酷炫效果
type -> 转场动画类型
subtype -> 转场动画方向
startProgress -> 动画起点进度(整体的百分比)
endProgress -> 动画终点进度(整体的百分比)
filter -> 自定义转场。
CAAnimationGroup 动画组,方便对于多动画的统一控制管理。
animations -> 所有动画效果元素的数组。
CABasicAnimation
在一般的应用开发中,基础动画可以满足大部分的开发需求,主要完成对于对象指定动画属性两个 Value 之间的动画过渡。
下面展示使用 CABasicAnimation 实现 位移、缩放、透明度、旋转、圆角 的核心代码
switch (button.tag) {
case 0:
// 位移动画
basicAni = [CABasicAnimation animationWithKeyPath:@”position”];
// 到达位置
// basicAni.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
basicAni.toValue = [NSValue valueWithCGPoint:CGPointMake(_mainLayer.position.x+100, _mainLayer.position.y+100)];
break;
case 1:
// 缩放动画
basicAni = [CABasicAnimation animationWithKeyPath:@”transform.scale”];
// 到达缩放
basicAni.toValue = @(0.1f);
break;
case 2:
// 透明度动画
basicAni = [CABasicAnimation animationWithKeyPath:@”opacity”];
// 透明度
basicAni.toValue=@(0.1f);
break;
case 3:
// 旋转动画
basicAni = [CABasicAnimation animationWithKeyPath:@”transform”];
//3D
basicAni.toValue=[NSValue valueWithCATransform3D:CATransform3DMakeRotation(M_PI_2+M_PI_4, 1, 1, 0)];
break;
case 4:
// 圆角动画
basicAni = [CABasicAnimation animationWithKeyPath:@”cornerRadius”];
// 圆角
basicAni.toValue=@(50);
break;
CASpringAnimation
CASpringAnimation 是 iOS9 引入的动画类,类似于 UIView 的 spring 动画,但是增加的质量,劲度系数等属相的扩展,继承自 CABaseAnimation,用法也比较简单:
#pragma mark ———————–CASpringAniamtion
– (void)initSpringAnimation {
CASpringAnimation *springAni = [CASpringAnimation animationWithKeyPath:@”position”];
springAni.damping = 2;
springAni.stiffness = 50;
springAni.mass = 1;
springAni.initialVelocity = 10;
springAni.toValue = [NSValue valueWithCGPoint:CGPointMake(200, 400)];
springAni.duration = springAni.settlingDuration;
[_mainLayer addAnimation:springAni forKey:@”springAnimation”];
}
CAKeyframeAnimation
CAKeyframeAnimation 和 CABasicAnimation 一样是 CApropertyAnimation 的子类,但是 CABasicAnimation 只能从一个数值 (fromValue) 变到另一个数值 (toValue) 或者添加一个增量数值(byValue),而 CAKeyframeAnimation 使用 values 数组可以设置多个关键帧,同时可以利用 path 可以进行位置或者锚点的动画操作
– (void)initKeyframeAnimation {
CAKeyframeAnimation *animation = nil;
if (self.animationIndex == 2) {// 晃动
animation = [CAKeyframeAnimation animationWithKeyPath:@”transform.rotation”];
animation.duration = 0.3;
animation.values = @[@(-(4) / 180.0*M_PI),@((4) / 180.0*M_PI),@(-(4) / 180.0*M_PI)];
animation.repeatCount=MAXFLOAT;
}else {// 曲线位移
animation = [CAKeyframeAnimation animationWithKeyPath:@”position”];
UIBezierPath *path = [UIBezierPath bezierPath];
[path moveToPoint:_mainLayer.position];
[path addCurveToPoint:CGPointMake(300, 500) controlPoint1:CGPointMake(100, 400) controlPoint2:CGPointMake(300, 450)];
animation.path = path.CGPath;
animation.duration = 1;
animation.removedOnCompletion = NO;
animation.fillMode = kCAFillModeForwards;
}
[_mainLayer addAnimation:animation forKey:@”keyFrameAnimation”];
}
CATransition
转场动画是一种显示样式向另一种显示样式过渡的效果, 系统给出的效果也很多,不过谨慎使用私有 API,防止被拒的悲剧. 具体有以下效果:
cube 方块
suckEffect 三角
rippleEffect 水波抖动
pageCurl 上翻页
pageUnCurl 下翻页
oglFlip 上下翻转
cameraIrisHollowOpen 镜头快门开
cameraIrisHollowClose 镜头快门开
– (void)initCATransitionAnimation {
CATransition *transition = [CATransition animation];
transition.type = @”rippleEffect”;
transition.subtype = kCATransitionFromLeft;
transition.duration = 1;
_mainLayer.contents = (__bridge id _Nullable)([UIImage imageNamed:@”example”].CGImage);
[_mainLayer addAnimation:transition forKey:@”transtion”];
}
CAAnimationGroup
在我们实际开发中,我们可能需要更加复杂的复合运动,那么需要给图层加多个动画,动画组也就应运而生,创建动画组也很简单,首先创建单个动画,然后将创建的多个动画添加到动画组,最后将动画组添加图层上就可以啦。
– (void)initAnimationGroup {
// 晃动动画
CAKeyframeAnimation *keyFrameAni = [CAKeyframeAnimation animationWithKeyPath:@”transform.rotation”];
keyFrameAni.values = @[@(-(4) / 180.0*M_PI),@((4) / 180.0*M_PI),@(-(4) / 180.0*M_PI)];
// 每一个动画可以单独设置时间和重复次数, 在动画组的时间基础上, 控制单动画的效果
keyFrameAni.duration = 0.3;
keyFrameAni.repeatCount= MAXFLOAT;
keyFrameAni.delegate = self;
// keyFrameAni.removedOnCompletion = NO;
// keyFrameAni.fillMode = kCAFillModeForwards;
// 位移动画
CABasicAnimation *basicAni = [CABasicAnimation animationWithKeyPath:@”position”];
// 到达位置
basicAni.byValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
//
basicAni.duration = 1;
basicAni.repeatCount = 1;
//
basicAni.removedOnCompletion = NO;
basicAni.fillMode = kCAFillModeForwards;
// 设置代理
basicAni.delegate = self;
// 动画时间
basicAni.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
CAAnimationGroup *aniGroup = [CAAnimationGroup animation];
aniGroup.animations = @[keyFrameAni,basicAni];
aniGroup.autoreverses = YES;
// 动画的表现时间和重复次数由动画组设置的决定
aniGroup.duration = 2;
aniGroup.repeatCount= 3;
// 使动画结束后停留在结束位置
// aniGroup.autoreverses = NO;
// aniGroup.removedOnCompletion = NO;
// aniGroup.fillMode = kCAFillModeForwards;
//
[_mainLayer addAnimation:aniGroup forKey:@”groupAnimation”];
}
总结
Core Animation 给我们展示的只是假象;layer 的 frame、bounds、position 不会在动画完毕后发生改变;UIView 封装的动画会真实修改 view 的一些属性。
本文总结的内容个人感觉还是比较浅的,但还是能满足日常开发要求的,当然一些要求比较高的,还需要大家对每个动画类进行深入的研究。
最后附上本文的 Demo 地址 : animation