一、CALayer
CALayer很多属性在修改时都能形成动画效果(不需要借助动画类),这种属性称为“隐式动画属性”。但是对于UIView的根图层而言属性的修改并不形成动画效果,因为很多情况下根图层更多的充当容器的做用,如果它的属性变动形成动画效果会直接影响子图层。
-
CALayer的属性中,如果一个被标记为Animatable,那么它具有以下两个特点:
1、直接对它赋值可能产生隐式动画;
2、我们的CAAnimation的keyPath可以设置为这个属性的名字。 -
可实现动画的属性:
坐标尺寸:bounds、frame(不支持隐私动画)、center
视图显示:backgroundColor、alpha、hidden
形态变化:transform 隐式属性动画的本质是这些属性的变动默认隐含了CABasicAnimation动画实现,详情大家可以参照Xcode帮助文档中“Animatable Properties”一节。
在CALayer中很少使用frame属性,因为frame本身不支持动画效果,通常使用bounds和position代替。
CALayer中透明度使用opacity表示而不是alpha;中心点使用position表示而不是center。
anchorPoint属性是图层的锚点,范围在(01,01)表示在x、y轴的比例,这个点永远可以同position(中心点)重合,当图层中心点固定后,调整anchorPoint即可达到调整图层显示位置的作用(因为它永远和position重合)
一、 CoreAnimation
在iOS中核心动画分为几类:基础动画、关键帧动画、动画组、转场动画。各个类的关系大致如下:
-
基础动画CABasicAnimation
- 步骤:1.初始化动画并设置动画属性 2.设置动画属性初始值(可以省略)、结束值以及其他动画属性 3.给图层添加动画
- 以SVProgress为例,起主要动画代码如下:
-(void) SVProgressRing {
CGPoint arcCenter = CGPointMake(200, 300);
UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter radius:30 startAngle:(CGFloat)-M_PI_2 endAngle:(CGFloat) (M_PI + M_PI_2) clockwise:YES];
CAShapeLayer *ringAnimatedLayer = [CAShapeLayer layer];
ringAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale];
ringAnimatedLayer.frame = CGRectMake(0.0f, 0.0f, arcCenter.x*2, arcCenter.y*2);
ringAnimatedLayer.fillColor = [UIColor clearColor].CGColor;
ringAnimatedLayer.strokeColor = [UIColor greenColor].CGColor;
ringAnimatedLayer.lineWidth = 4;
ringAnimatedLayer.lineCap = kCALineCapRound;
ringAnimatedLayer.lineJoin = kCALineJoinBevel;
ringAnimatedLayer.path = smoothedPath.CGPath;
ringAnimatedLayer.strokeStart = 0;
ringAnimatedLayer.strokeEnd = 0.6;
CAShapeLayer *backgroundLayer = [CAShapeLayer layer];
backgroundLayer.fillColor = [UIColor clearColor].CGColor;
backgroundLayer.strokeColor = [[UIColor greenColor] colorWithAlphaComponent:0.1].CGColor;
backgroundLayer.lineWidth = 4;
backgroundLayer.path = smoothedPath.CGPath;
backgroundLayer.strokeStart = 0;
backgroundLayer.strokeEnd = 1;
[self.view.layer addSublayer:backgroundLayer];
[self.view.layer addSublayer:ringAnimatedLayer];
// 0.015 到 0.515 是一个圆 从0.015 擦除到 0.515,从0.515到1依然是实线
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
animation.fromValue = @0.0;
animation.toValue = @1;
animation.duration = 3;
animation.repeatCount = INFINITY;
animation.removedOnCompletion = NO;
// animation.timingFunction = LINEF
[ringAnimatedLayer addAnimation:animation forKey:@"progress"];
}
-
动画组
-
关键帧动画CAKeyframeAnimation
-
转场动画CATransition
-
CASpringAnimation
-
逐帧动画
- 虽然在核心动画没有直接提供逐帧动画类型,但是却提供了用于完成逐帧动画的相关对象CADisplayLink。CADisplayLink是一个计时器,但是同NSTimer不同的是,CADisplayLink的刷新周期同屏幕完全一致。例如在iOS中屏幕刷新周期是60次/秒,CADisplayLink刷新周期同屏幕刷新一致也是60次/秒,这样一来使用它完成的逐帧动画(又称为“时钟动画”)完全感觉不到动画的停滞情况。
二、UIView 封装的方法
-
非block
- UIView本身对于基本动画和关键帧动画、转场动画都有相应的封装,在对动画细节没有特殊要求的情况下使用起来也要简单的多。
执行动画所需要的工作由UIView类自动完成,但仍要在希望执行动画时通知视图,为此需要将改变属性的代码放在[UIView beginAnimations:nil context:nil]和[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代表使用视图缓存,性能较好
- UIView本身对于基本动画和关键帧动画、转场动画都有相应的封装,在对动画细节没有特殊要求的情况下使用起来也要简单的多。
- (void) animate {
//首尾式动画
[UIView beginAnimations:nil context:nil];
//执行动画
//设置动画执行时间
[UIView setAnimationDuration:2.0];
//设置代理
[UIView setAnimationDelegate:self];
//设置动画执行完毕调用的事件
[UIView setAnimationDidStopSelector:@selector(didStopAnimation)];
self.customView.center=CGPointMake(200, 300);
[UIView commitAnimations];
}
-
block方式
[UIView animateWithDuration: delay: options: animations: completion:^(BOOL finished) {}]
以上方法中的options一项需要传入一个枚举,这个枚举大概控制的是这几个要素:当前动画嵌套中的动画执行随时间的快慢种类(先快后慢等..)。动画要一直重复吗。如果我使用转场动画那么我用哪种转场效果。还有子动画嵌套在父动画中时我们如何对待父动画中的相同选项等等
- UIViewAnimationOptions(可以同时选择多个进行设置):
UIViewAnimationOptionLayoutSubviews:动画过程中保证子视图跟随运动。提交动画的时候布局子控件,表示子控件将和父控件一同动画。
UIViewAnimationOptionAllowUserInteraction:动画过程中允许用户交互。
UIViewAnimationOptionBeginFromCurrentState:所有视图从当前状态开始运行。
UIViewAnimationOptionRepeat:重复运行动画。
UIViewAnimationOptionAutoreverse :动画运行到结束点后仍然以动画方式回到初始点。执行动画回路,前提是设置动画无限重复
UIViewAnimationOptionOverrideInheritedDuration:忽略嵌套动画时间设置。忽略外层动画嵌套的时间变化曲线
UIViewAnimationOptionOverrideInheritedCurve:忽略嵌套动画速度设置。通过改变属性和重绘实现动画效果,如果key没有提交动画将使用快照
UIViewAnimationOptionAllowAnimatedContent:动画过程中重绘视图(注意仅仅适用于转场动画)。
UIViewAnimationOptionShowHideTransitionViews:视图切换时直接隐藏旧视图、显示新视图,而不是将旧视图从父视图移除(仅仅适用于转场动画)用显隐的方式替代添加移除图层的动画效果
UIViewAnimationOptionOverrideInheritedOptions :不继承父动画设置或动画类型。忽略嵌套继承的选项
----------------------------------------------------------------------------
2.动画速度控制(可从其中选择一个设置)时间函数曲线相关时间曲线函数
UIViewAnimationOptionCurveEaseInOut:动画先缓慢,然后逐渐加速。
UIViewAnimationOptionCurveEaseIn :动画逐渐变慢。
UIViewAnimationOptionCurveEaseOut:动画逐渐加速。
UIViewAnimationOptionCurveLinear :动画匀速执行,默认值。
-----------------------------------------------------------------------------
3.转场类型(仅适用于转场动画设置,可以从中选择一个进行设置,基本动画、关键帧动画不需要设置)转场动画相关的
UIViewAnimationOptionTransitionNone:没有转场动画效果。
UIViewAnimationOptionTransitionFlipFromLeft :从左侧翻转效果。
UIViewAnimationOptionTransitionFlipFromRight:从右侧翻转效果。
UIViewAnimationOptionTransitionCurlUp:向后翻页的动画过渡效果。
UIViewAnimationOptionTransitionCurlDown :向前翻页的动画过渡效果。
UIViewAnimationOptionTransitionCrossDissolve:旧视图溶解消失显示下一个新视图的效果。
UIViewAnimationOptionTransitionFlipFromTop :从上方翻转效果。
UIViewAnimationOptionTransitionFlipFromBottom:从底部翻转效果。
三 UIView封装的动画与CALayer动画的对比
UIView封装的动画执行完毕之后不会反弹。即如果是通过CALayer核心动画改变layer的位置状态,表面上看虽然已经改变了,但是实际上它的位置是没有改变的(可使用动画代理防止动画回弹)。使用UIView和CALayer都能实现动画效果,但是在真实的开发中,一般还是主要使用UIView封装的动画,而很少使用CALayer的动画。