ios的动画的技术方案很多,UIview、CoreAnimation,
(1)在UIview的分类中的的类方法中有+animationWithDuration:及其它类似的方法,可以实现一些比较基础的动画可以对UIview的属性使用,如frame、backgroundColor等
(2)CoreAnimation框架中CAAnimation类的子类,CABasicAnimation、CAPropertyAnimation、CAKeyFrameAnimation实现强大的动画。
(3)基于CADisplayLink的动画,与CoreGraphic结合也可以实现动画效果。
隐式事务
隐式动画是基于CALayer层的,UIKit框架是禁用隐式事务动画的,UIview与CALayer的关系,UIView是负责交互而CALayer是负责显示图层的。
隐式事务是CoreAnimation的一部分,是对layer-tree进行原子更新为render-tree的机制,由CoreAnimation来帮助自动创建完事务,当前线程的runloop下次循环就会自动commit,如果当前线程没有runloop,或者runloop被阻塞,则应该显示的创建显示事务。手动创建CATransaction动画事务。
@property(nonatomic,strong)CALayer *testLayer;
-(void)viewDidLoad{
[super viewDidLoad];
self.testLayer = [CALayer layer];
self.testLayer.frame = CGRectMake(50, 100, 100, 100);
self.testLayer.backgroundColor = [UIColor redColor].CGColor;
[self.view.layer addSublayer:self.testLayer];
}
-(void)buttonClick{
//会有一闪而过的动画,隐式动画
self.testLayer.backgroundColor = [UIColor blueColor].CGColor;
}
//显示动画
-(void)buttonClick{
//1.开启显示事务
[CATransaction begin];
NSLog(@"=====start");
//2.设置动画时间
[CATransaction setAnimationDuration:2];
//4.设置回调
[CATransaction setCompletionBlock:^{
//5.也可以嵌套事务
//背景色改变后,改变圆角
[CATransaction setAnimationDuration:1];
self.testLayer.cornerRadius = 10;
NSLog(@"=====end");
}];
self.testLayer.backgroundColor = [UIColor blueColor].CGColor;
NSLog(@"=====....");
//3.提交事务
[CATransaction commit];
}
CALayer可以对事务动画做出相应是因为CALayer的实例方法-actionForKey:可以对其进行相应,返回对应的方法。
但是对于UIView来说,UIview作为CAlayer的代理,则根据名称来获取action对象,会遵循以下顺序
1.如果view有代理,则调用代理方法-actionForLayer:forKey
2.检查layer的actions字典
3.检查layer的style层级中每个actions字典
4.调用layer的类方法+defaultActionForKey
代理方法
-(id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event{
NSLog(@"event=%@",event,);
return layer.actions[event];
}
打印
2019-09-27 11:12:38.863194+0800 CADemo[61157:1358546] event=backgroundColor
2019-09-27 11:12:38.865429+0800 CADemo[61157:1358546] event=onOrderIn
2019-09-27 11:12:38.870547+0800 CADemo[61157:1358546] event=onLayout
2019-09-27 11:12:41.174068+0800 CADemo[61157:1358546] =====start
2019-09-27 11:12:41.175396+0800 CADemo[61157:1358546] event=backgroundColor
2019-09-27 11:12:41.176373+0800 CADemo[61157:1358546] =====....
2019-09-27 11:12:43.177419+0800 CADemo[61157:1358546] event=cornerRadius
2019-09-27 11:12:43.177659+0800 CADemo[61157:1358546] =====end
启动时会触发-actionForLayer:forKey这个代理方法
当点击按钮,开始事务动画时,触发代理方法,首先执行backgroundColor这个动画,然后再修改圆角。
应用
监听键盘,上移被遮挡的View
- (void)viewDidLoad {
[super viewDidLoad];
self.defalutRect = self.textField.frame;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHiden:) name:UIKeyboardWillHideNotification object:nil];
}
-(void)keyboardWillShow:(NSNotification *)noti{
NSLog(@"noti.userInfo=%@",noti.userInfo);
NSDictionary*info=[noti userInfo];
CGRect rect=[[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; //键盘上移后的frame
CGRect textFrame = self.textField.frame;
//键盘与textfiled会紧贴
// textFrame.origin.y = rect.origin.y -textFrame.size.height -1 ;
// 键盘与textfiled不会紧贴,会有原先与底部的距离
textFrame.origin.y = textFrame.origin.y - rect.size.height;
self.textField.frame = textFrame;
self.textField.delegate = self;
self.textField.returnKeyType = UIReturnKeyDone;
}
-(void)keyboardWillHiden:(NSNotification *)noti{
NSLog(@"noti.userInfo=%@",noti.userInfo);
self.textField.frame = self.defalutRect;
}
NSNotification的userInfo中存储了键盘与frame相关的信息。
UIKeyboardFrameBeginUserInfoKey和UIKeyboardFrameEndUserInfoKey对应的是键盘在进行交互前和和交互后的frame,没有交互前的是在屏幕底部,且根据UIKeyboardAnimationDurationUserInfoKey 对应的是动画持续的时间,所以这里键盘弹出是由一个0.25s的动画。
那么如何开启和关闭这个动画呢?
-(void)keyboardWillShow:(NSNotification *)noti{
[UIView setAnimationsEnabled:NO];
//do something
//关闭后记得打开
[UIView setAnimationsEnabled:YES];
}
通过UIview的类方法+setAnimationsEnabled:来忽略动画。