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:來忽略動畫。