當然,我不知道是什麼引擎蓋下到底會發生因爲UIKit的不是開源的,我不會在蘋果工作,但這裏有一些想法:
基於塊的UIView
之前引入動畫方式,動畫的觀點看起來像這一點,這些方法實際上仍然可用:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
myView.center = CGPointMake(300, 300);
[UIView commitAnimations];
認識到這一點,我們可以實現我們自己的基於塊的動畫製作方法是這樣的:
+ (void)my_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
animations();
[UIView commitAnimations];
}
......這與現有的animateWithDuration:animations:
方法完全相同。
將塊排除在等式之外,很明顯,必須有某種全局動畫狀態,UIView
隨後會在動畫塊內完成動畫變化(動畫)屬性的動畫。這必須是某種堆棧,因爲你可以嵌套動畫塊。
實際的動畫是通過核心動畫,這在層級進行工作 - 每個UIView
有後盾CALayer
實例,它是負責動畫和合成,而鑑於大多隻是處理觸摸事件和座標系統轉換。
我不會在這裏詳細介紹Core Animation的工作原理,您可能需要閱讀Core Animation Programming Guide。實質上,它是一個系統,可以在層次樹中動畫變化,而無需明確計算每個關鍵幀(實際上,從Core Animation獲取中間值實際上相當困難,通常只需指定值和值,持續時間等,然後讓系統照顧細節)。
因爲UIView
基於CALayer
,其許多屬性實際上是在底層實現的。例如,當您設置或獲得view.center
時,與view.layer.location
相同,更改其中任一個也會更改另一個。
層可以與CAAnimation
明確動畫(其是具有許多具體的實現,如用於CABasicAnimation
簡單的事情和CAKeyframeAnimation
用於更復雜的東西一個抽象類)。
那麼一個UIView
屬性設置器可以做什麼來實現動畫塊中的「神奇」動畫變化動畫?讓我們看看我們是否可以重新實現其中之一,爲了簡單起見,讓我們使用setCenter:
。
首先,這裏從上面使用全局CATransaction
的my_animateWithDuration:animations:
方法的修改版本,這樣我們就可以在我們的setCenter:
方法找出動畫應該多久採取:
- (void)my_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[CATransaction begin];
[CATransaction setAnimationDuration:duration];
animations();
[CATransaction commit];
}
注意我們不再使用beginAnimations:...
和commitAnimations
,所以沒有做任何事情,什麼都不會動畫。
現在,讓我們來覆蓋setCenter:
在UIView
子類:
@interface MyView : UIView
@end
@implementation MyView
- (void)setCenter:(CGPoint)position
{
if ([CATransaction animationDuration] > 0) {
CALayer *layer = self.layer;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [layer valueForKey:@"position"];
animation.toValue = [NSValue valueWithCGPoint:position];
layer.position = position;
[layer addAnimation:animation forKey:@"position"];
}
}
@end
在這裏,我們建立了一個明確的動畫使用的Core Animation動畫是底層的location
財產。動畫的持續時間將自動從CATransaction
中獲取。讓我們來嘗試一下:
MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self my_animateWithDuration:4.0 animations:^{
NSLog(@"center before: %@", NSStringFromCGPoint(myView.center));
myView.center = CGPointMake(300, 300);
NSLog(@"center after : %@", NSStringFromCGPoint(myView.center));
}];
我不是說這正是UIView
動畫系統是如何工作的,它只是說明如何它可以原則工作。