您的位置:首页 > 移动开发 > IOS开发

Core Animation 的隐式动画

2015-10-22 17:04 531 查看
场景重现:为什么UIView或者CALayer改变他们相关属性,他们就会平缓的做些动画,这时你并没有调用相关动画代码,想过这个问题没?

那我们来看看系统究竟帮我们做了哪些东西。

如果你自己设置了动画类型和动画时间,表现出来就是你指定的动画,如果没有,那么系统会自动帮我们做了动画类型和动画时间(这就是隐式动画)。

问题有来了,什么决定了动画时间和动画类型。

1、动画时间: 当前”事务” 决定的 ==>“事务“是通过CATransaction类来做管理。

2、动画类型:由图层的行为决定的。

note:CATransaction概念

CATransaction没有属性或者实例方法,并且也不能用+alloc和-init方法创建它。但是可以用+begin和+commit分别来入栈或者出栈

隐式动画真正背后执行的原因:

Core Animation在每个run loop周期中自动开始一次新的事务(run loop是iOS负责收集用户输入,处理定时器或者网络事件并且重新绘制屏幕的东西),即使你不显式的用[CATransaction begin]开始一次事务,任何在一次run loop循环中属性的改变都会被集中起来,然后做一次0.25秒的动画。

如果你不用系统的动画模式,要自定义,最原始的样子就是下面

- (IBAction)changeColor
{
//begin a new transaction
[CATransaction begin];
//set the animation duration to 1 second
[CATransaction setAnimationDuration:1.0];
//randomize the layer background color
CGFloat red = arc4random() / (CGFloat)INT_MAX;
CGFloat green = arc4random() / (CGFloat)INT_MAX;
CGFloat blue = arc4random() / (CGFloat)INT_MAX;
self.colorLayer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;
//commit the transaction
[CATransaction commit];
}


上面讨论所有的问题,都是动画时间相关的,还有个影响动画的因素,刚才的第二点:动画类型(由图层决定了)

动画类型(由图层决定)

先上代码,让大家看看问题。

@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIView *layerView;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.layerView.layer.backgroundColor = [UIColor blueColor].CGColor;//这里直接给view的layer层设置了颜色
}
- (IBAction)changeColor
{
//begin a new transaction
[CATransaction begin];
//set the animation duration to 1 second
[CATransaction setAnimationDuration:1.0];
//randomize the layer background color
CGFloat red = arc4random() / (CGFloat)INT_MAX;
CGFloat green = arc4random() / (CGFloat)INT_MAX;
CGFloat blue = arc4random() / (CGFloat)INT_MAX;
self.layerView.layer.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:1.0].CGColor;
//commit the transaction
[CATransaction commit];
}


运行程序,你会发现当按下按钮,图层颜色瞬间切换到新的值,而不是之前平滑过渡的动画。发生了什么呢?

先给结论:

1、是给UIView做的动画,那么一定要用UIView层的动画模式(UIView有两个方法,+beginAnimations:context:和+commitAnimations)。

2、是给CALayer做动画,那么一定用CATransaction begin相关的方法。

原因就是上面程序出现的问题:UIView关联的图层禁用了隐式动画,造成了动画没有。

再深入一点,隐式动画是如何被UIKit禁用掉呢?

解决这个问题,先看看这个系统大概是如何实现隐式动画?

CALayer的属性被修改时候,layer首先检测它是否有委托,

1、有代理对象,它会调用-actionForKey:方法,

2、没有代理对象,去找图层动画的action(以那种动画展现),它最后最后会调用,defaultActionForKey:这个应该就是隐式动画效果

很显然,UIView做了layer的代理,再UIView内部实行了-actionForKey:方法,估计如果不是调用UIView的动画方法时,实现的协议方法actionForKey:里面返回一个nil,如果调用UIView的自己的动画方法,就返回值,产生了动画。

上面也可以总结一点:UIKit建立在Core Animation(默认对所有东西都做动画)之上,所有Core Animation的动画方法,再UIKit层都有对应的。

比如:

1、UIView有两个方法,+beginAnimations:context:和+commitAnimations,和CATransaction的+begin和+commit方法类似。

2、 UIView的block的动画允许你在动画结束的时候提供一个完成的动作。CATranscation接口提供的+setCompletionBlock:方法也有同样的功能。

在上面讲系统大概是如何实现隐式动画,说到”没有代理对象,去找图层动画的action(以那种动画展现)”,如果我不想用系统提供的动画效果,有没有其他的动画效果可以执行。

@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIView *layerView;
@property (nonatomic, weak) IBOutlet CALayer *colorLayer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//create sublayer
self.colorLayer = [CALayer layer];
self.colorLayer.frame = CGRectMake(50.0f, 50.0f, 100.0f, 100.0f);
self.colorLayer.backgroundColor = [UIColor blueColor].CGColor;
//add a custom action
CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromLeft;
self.colorLayer.actions = @{@"backgroundColor": transition};
//add it to our view
[self.layerView.layer addSublayer:self.colorLayer];
}
@end


上面就做到了自定义action(动画效果)。

注意:这里要提醒大家:CATransition和CATransaction的区别。



这个就能看出CATransition和CATransaction真正的区别了吧。

只要记住后面单词的区别:

action结尾的就是开始动画、提交动画(action行为的事情)

sition结尾的就是名词,就是自定义动画相关
8bde
的属性,
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ios 动画