Tất nhiên tôi không biết chính xác những gì xảy ra dưới mui xe vì UIKit không phải là mã nguồn mở và tôi không làm việc tại Apple, nhưng đây là một số ý tưởng:
Trước khi khối dựa trên UIView
phương pháp hoạt hình đã được giới thiệu, xem hiệu ứng động trông như thế này, và các phương pháp đó thực sự vẫn còn có sẵn:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
myView.center = CGPointMake(300, 300);
[UIView commitAnimations];
Biết được điều này, chúng ta có thể thực hiện khối dựa trên phương pháp hoạt hình của riêng của chúng tôi như thế này:
+ (void)my_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
animations();
[UIView commitAnimations];
}
... sẽ thực hiện chính xác giống như phương pháp animateWithDuration:animations:
hiện tại. Lấy một khối trạng thái hoạt hình toàn cục mà UIView
sau đó sử dụng để tạo ra các thay đổi cho các thuộc tính (có thể hoạt hình) của nó khi chúng được thực hiện trong một khối hoạt ảnh. Điều này phải là một số loại ngăn xếp, bởi vì bạn có thể có khối hoạt hình lồng nhau.
Hoạt ảnh thực tế được thực hiện bởi Core Animation, hoạt động ở cấp lớp - mỗi UIView
có bản sao CALayer
thể hiện hoạt ảnh và tổng hợp, trong khi chế độ xem chủ yếu chỉ xử lý các sự kiện chạm và chuyển đổi hệ thống tọa độ.
Tôi sẽ không đi sâu vào chi tiết tại đây về cách hoạt ảnh của Core Animation, bạn có thể muốn đọc Core Animation Programming Guide cho điều đó. Về cơ bản, đó là một hệ thống để tạo ra các thay đổi trong cây lớp, mà không tính toán rõ ràng mọi khung hình chính (và thực sự khá khó để có được các giá trị trung gian từ Core Animation, bạn thường chỉ định từ và đến các giá trị, thời lượng, v.v. chăm sóc các chi tiết).
Vì UIView
được dựa trên CALayer
, nhiều thuộc tính của nó thực sự được triển khai trong lớp cơ bản. Ví dụ: khi bạn đặt hoặc nhận được view.center
, tương tự như view.layer.location
và việc thay đổi một trong hai tùy chọn này cũng sẽ thay đổi cài đặt khác.
Layers có thể rõ ràng hoạt hình với CAAnimation
(đó là một lớp trừu tượng mà có một số triển khai cụ thể, như CABasicAnimation
cho mọi thứ đơn giản và CAKeyframeAnimation
cho các công cụ phức tạp hơn).
Vậy điều gì có thể là UIView
thiết lập thuộc tính làm để thực hiện các thay đổi hoạt hình "kỳ diệu" trong khối hoạt ảnh? Hãy xem liệu chúng ta có thể triển khai lại một trong số chúng hay không, vì mục đích đơn giản, hãy sử dụng setCenter:
.
Thứ nhất, đây là một phiên bản sửa đổi của phương pháp my_animateWithDuration:animations:
từ trên cao mà sử dụng toàn cầu CATransaction
, để chúng ta có thể tìm hiểu trong phương pháp setCenter:
của chúng tôi hoạt hình được cho là bao lâu để thực hiện:
- (void)my_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[CATransaction begin];
[CATransaction setAnimationDuration:duration];
animations();
[CATransaction commit];
}
Lưu ý rằng chúng tôi không sử dụng beginAnimations:...
và commitAnimations
nữa, vì vậy mà không làm bất kỳ điều gì khác, sẽ không có hoạt ảnh nào.
Bây giờ, chúng ta hãy ghi đè setCenter:
trong một lớp con 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
Ở đây, chúng tôi thiết lập một rõ ràng hoạt hình sử dụng Core Animation mà sinh động sở hữu location
lớp cơ bản của. Thời lượng của hoạt ảnh sẽ tự động được lấy từ CATransaction
. Hãy thử nó ra:
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));
}];
Tôi không nói rằng đây là chính xác cách thức hệ thống UIView
hoạt hình hoạt động, nó chỉ để hiển thị như thế nào nó có thể làm việc trên nguyên tắc.