iOS引入动画效果可以使我们的软件得到更好的用户体验,因此动画的深入研究无疑对于开发者一个很好的加分项。
常见的iOS对动画的操作分为两类:
CALayer层的操作
UIView的操作
二者有何区别
UIView里面包含有一个CALayer层
UIView之所以能够在屏幕上显示出来,完全因为其内部拥有一个CALayer层
CALayer层的操作更底层更轻量级、性能更高。
UIView动画执行完毕之后不会反弹,而CALayer动画改变layer的状态位置,出现假象的改变,其实实际位置并没有改变
开发时如何选择二者:
每个UIView的操作其实是对CALayer层的封装,比较简单,优先选择UIView动画操作。
操作CALayer层更直接,能实现UIView所不能实现的功能
UIView动画
一、首尾式动画(经典的不能再经典啦)
[UIView beginAnimations:nil context:nil] ;
//需要执行动画的核心代码
//设置动画执行时间
[UIView setAnimationDuration:2.0];
//设置代理
[UIView setAnimationDelegate:self];
//设置动画执行完毕调用的事件
[UIView setAnimationDidStopSelector:@selector(didStopAnimation)];
self.customView.center=CGPointMake(200, 300);
[UIView commitAnimations];
+ (void)setAnimationDelegate:(id)delegate 设置动画代理对象,当动画开始或者结束时会发消息给代理对象
+ (void)setAnimationWillStartSelector:(SEL)selector 当动画即将开始时,执行delegate对象的selector,并且把beginAnimations:context:中传入的参数传进selector
+ (void)setAnimationDidStopSelector:(SEL)selector 当动画结束时,执行delegate对象的selector,并且把beginAnimations:context:中传入的参数传进selector
+ (void)setAnimationDuration:(NSTimeInterval)duration 动画的持续时间,秒为单位
+ (void)setAnimationDelay:(NSTimeInterval)delay 动画延迟delay秒后再开始
+ (void)setAnimationStartDate:(NSDate *)startDate 动画的开始时间,默认为now
+ (void)setAnimationCurve:(UIViewAnimationCurve)curve 动画的节奏控制
+ (void)setAnimationRepeatCount:(float)repeatCount 动画的重复次数
+ (void)setAnimationRepeatAutoreverses:(BOOL)repeatAutoreverses 如果设置为YES,代表动画每次重复执行的效果会跟上一次相反
+ (void)setAnimationTransition:(UIViewAnimationTransition)transition forView:(UIView *)view cache:(BOOL)cache 设置视图view的过渡效果, transition指定过渡类型, cache设置YES代表使用视图缓存,性能较好
二、block动画(依旧也经典)
+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
duration:动画的持续时间
delay:动画延迟delay秒后开始
options:动画的节奏控制
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
+ (void)transitionWithView:(UIView *)view duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion
duration:动画的持续时间
view:需要进行转场动画的视图
options:转场动画的类型
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion
duration:动画的持续时间
options:转场动画的类型
animations:将改变视图属性的代码放在这个block中
completion:动画结束后,会自动调用这个block
options参数的详细的枚举
typedef NS_OPTIONS(NSUInteger, UIViewAnimationOptions) {
UIViewAnimationOptionLayoutSubviews = 1 << 0,
UIViewAnimationOptionAllowUserInteraction = 1 << 1, // turn on user interaction while animating
UIViewAnimationOptionBeginFromCurrentState = 1 << 2, // start all views from current value, not initial value
UIViewAnimationOptionRepeat = 1 << 3, // repeat animation indefinitely
UIViewAnimationOptionAutoreverse = 1 << 4, // if repeat, run animation back and forth
UIViewAnimationOptionOverrideInheritedDuration = 1 << 5, // ignore nested duration
UIViewAnimationOptionOverrideInheritedCurve = 1 << 6, // ignore nested curve
UIViewAnimationOptionAllowAnimatedContent = 1 << 7, // animate contents (applies to transitions only)
UIViewAnimationOptionShowHideTransitionViews = 1 << 8, // flip to/from hidden state instead of adding/removing
UIViewAnimationOptionOverrideInheritedOptions = 1 << 9, // do not inherit any options or animation type
UIViewAnimationOptionCurveEaseInOut = 0 << 16, // default
UIViewAnimationOptionCurveEaseIn = 1 << 16,
UIViewAnimationOptionCurveEaseOut = 2 << 16,
UIViewAnimationOptionCurveLinear = 3 << 16,
UIViewAnimationOptionTransitionNone = 0 << 20, // default
UIViewAnimationOptionTransitionFlipFromLeft = 1 << 20,
UIViewAnimationOptionTransitionFlipFromRight = 2 << 20,
UIViewAnimationOptionTransitionCurlUp = 3 << 20,
UIViewAnimationOptionTransitionCurlDown = 4 << 20,
UIViewAnimationOptionTransitionCrossDissolve = 5 << 20,
UIViewAnimationOptionTransitionFlipFromTop = 6 << 20,
UIViewAnimationOptionTransitionFlipFromBottom = 7 << 20,
} NS_ENUM_AVAILABLE_IOS(4_0);
CALayer层动画
CALayer的两个属性:
position位置(原点为父类的(0,0))
anchorPoint 锚点(默认原点在自身长和宽各一半的交点(0.5,0.5))
什么是隐式动画
简单说,每个控件都有一个自带的CALayer层,这个层称为根层,与之相对于的就是非根层,非根层的的属性改变就会默认引发动画,这样的动画就可以称为隐式动画
若项目需求要求不能够动画效果,如何关闭隐式动画?
[CATransaction begin];
[CATransaction setDisableActions:YES];
//......这里修改你想修改的Layer属性就不会产生默认的隐式动画
[CATransaction commit];
Layer层的动画分类
CAAnimation是所有动画类的父类,它和CAPropertyAnimation不能直接使用,应该使用它的子类CABasicAnimation、CAKeyframeAnimation、CATransition、CAAnimationGroup
CABasicAnimation基础动画
fromValue:keyPath相应属性值的初始值
toValue:keyPath相应属性的结束值
byValue : 增加多少值(注意对比toValue的意思)
keyPath内容是CALayer的可动画Animation属性
// 1.创建动画对象
CABasicAnimation *anim = [CABasicAnimation animation];
// 2.设置动画对象
// keyPath决定了执行怎样的动画, 调整哪个属性来执行动画
anim.keyPath = @"transform.translation.x";
anim.toValue = @(100);
//执行的时间
anim.duration = 2.0;
//加入下面两行,当动画结束时,layer所在的位置不会回到初始位置
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeForwards;
// 3.添加动画
[self.layer addAnimation:anim forKey:nil];
CAKeyframeAnimation关键帧动画
CAKeyframeAnimation是CABasicAnimation的升级版,CABasicAnimation只能改变一组属性动画就停止了,而CAKeyframeAnimation可以运行关于一个属性的一个数组的数据(这里需要特别注意是同一个属性的一组数据)
values:所有的值
path:路线
keyTimes:可以为对应的关键帧制定对应的时间点,取值范围是0到1.0
注意:path和values二者是相互排斥的,二者选取一个即可
values例子:
CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
anim.keyPath = @"transform.rotation";
anim.values = array;
anim.duration = 0.25;
// 动画的重复执行次数
anim.repeatCount = MAXFLOAT;
// 保持动画执行完毕后的状态
anim.removedOnCompletion = NO;
anim.fillMode = kCAFillModeForwards;
[self.redView.layer addAnimation:anim forKey:nil];
path例子:
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;
CGPathRelease(path);
// 设置动画的执行节奏
anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
anim.delegate = self;
[self.redView.layer addAnimation:anim forKey:nil];
CAAnimationGroup 动画组
我们上面两个动画类都是只能对同一个属性进行修改产生动画,而不能同时修改两个参数属性。所有就引入了CAAnimationGroup动画组
最经典的莫过于:边旋转边缩放边移动的动画效果,其实就是前面的基础动画加入到动画组形成的
// 1.创建旋转动画对象
CABasicAnimation *rotate = [CABasicAnimation animation];
rotate.keyPath = @"transform.rotation";
rotate.toValue = @(M_PI);
// 2.创建缩放动画对象
CABasicAnimation *scale = [CABasicAnimation animation];
scale.keyPath = @"transform.scale";
scale.toValue = @(0.0);
// 3.平移动画
CABasicAnimation *move = [CABasicAnimation animation];
move.keyPath = @"transform.translation";
move.toValue = [NSValue valueWithCGPoint:CGPointMake(100, 100)];
// 4.将所有的动画添加到动画组中
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = @[rotate, scale, move];
group.duration = 2.0;
group.removedOnCompletion = NO;
group.fillMode = kCAFillModeForwards;
[self.myvie.layer addAnimation:group forKey:nil];
CATransition转场动画
提供移除屏幕和移入屏幕的动画效果
/** 转场动画代码 */
// 创建转场动画对象
CATransition *anim = [CATransition animation];
// 设置转场类型
anim.type = @"pageCurl";
// 设置动画的方向
anim.subtype = kCATransitionFromLeft;
anim.duration = 3;
[_imageV.layer addAnimation:anim forKey:nil];
- type:动画过渡类型
- subtype:动画过渡方向
附一张type参照表
+(void)transitionWithView:(UIView*)view duration:(NSTimeInterval)duration options:
(UIViewAnimationOptions)options
animations:(void(^)(void))animations
completion:(void(^)(BOOLfinished))completion;
- duration:动画的持续时间
- view:需要进行转场动画的视图
- options:转场动画的类型
- animations:将改变视图属性的代码放在这个block中
- completion:动画结束后,会自动调用这个block
+ (void)transitionFromView:(UIView*) fromView
toView:(UIView*) toViewduration:(NSTimeInterval)durationoptions:(UIViewAnimationOptions) options
completion:(void(^)(BOOLfinished))completion;
- duration:动画的持续时间
- options:转场动画的类型
- animations:将改变视图属性的代码放在这个block中
- completion:动画结束后,会自动调用这个block
动画代理
动画也是存在代理的,实现代理可以在动画开始的时候调用和动画结束的时候调用的时候做些事情
anim.delegate = self;
#pragma mark 动画开始的时候调用
- (void)animationDidStart:(CAAnimation *)anim
{
}
#pragma mark 动画结束的时候调用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
}