2013-03-02 33 views
14

Tôi mới sử dụng lập trình Objective-C/iOS và tôi đang cố gắng hiểu cách hoạt ảnh của UIView hoạt động dưới mui xe.Cách hoạt ảnh của UIView với các khối hoạt động dưới mui xe

Nói rằng tôi có một mã như thế này:

[UIView animateWithDuration:2.0 animations:^{ 
    self.label.alpha = 1.0; 
}]; 

Điều đó được thông qua như là một cuộc tranh cãi animations là một khối Objective-C (cái gì đó như lambdas/chức năng ẩn danh trong các ngôn ngữ khác) có thể được thực hiện và sau đó nó thay đổi thuộc tính alpha của label từ giá trị hiện tại thành 1.0.

Tuy nhiên, khối không chấp nhận đối số tiến trình hoạt ảnh (nói từ 0.0 đến 1.0 hoặc từ 0 đến 1000). Câu hỏi của tôi là cách khung hoạt ảnh sử dụng khối này để biết về các khung trung gian, vì khối chỉ xác định trạng thái cuối cùng.

EDIT: Câu hỏi của tôi là khá về dưới mui xe hoạt động của animateWithDuration phương pháp chứ không phải là cách để sử dụng nó.

giả thuyết của tôi về cách animateWithDuration mã số hoạt động như sau:

  1. animateWithDuration kích hoạt một số loại trạng thái đặc biệt cho tất cả các đối tượng xem, trong đó thay đổi không thực sự thực hiện nhưng chỉ đăng ký.
  2. nó thực thi khối và thay đổi được đăng ký.
  3. nó truy vấn đối tượng dạng xem cho trạng thái đã thay đổi và lấy lại giá trị ban đầu và đích và do đó biết thuộc tính cần thay đổi và phạm vi nào để thực hiện thay đổi.
  4. tính toán các khung hình trung gian, dựa trên thời lượng và giá trị ban đầu/mục tiêu và kích hoạt hoạt ảnh.

Ai đó có thể làm sáng tỏ liệu animateWithDuration có thực sự hoạt động theo cách như vậy không?

Trả lời

16

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).

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:...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.

1

Các giá trị khung trung gian không được chỉ định; hình ảnh động của các giá trị (alpha trong trường hợp này, nhưng cũng có màu sắc, vị trí, vv) được tạo tự động giữa giá trị đã đặt trước đó và giá trị đích được đặt bên trong khối hoạt ảnh. Bạn có thể ảnh hưởng đến đường cong bằng cách chỉ định các tùy chọn sử dụng animateWithDuration:delay:options:animations:completion: (mặc định là UIViewAnimationOptionCurveEaseInOut, tức là tốc độ thay đổi giá trị sẽ tăng tốc và giảm tốc).

Lưu ý rằng mọi thay đổi hoạt ảnh được đặt trước đó sẽ hoàn thành trước, nghĩa là mỗi khối hoạt ảnh chỉ định hoạt ảnh mới từ giá trị kết thúc trước đó sang giá trị mới. Bạn có thể chỉ định UIViewAnimationOptionBeginFromCurrentState để bắt đầu hoạt ảnh mới từ trạng thái của hoạt ảnh đang diễn ra.

0

Điều này sẽ thay đổi thuộc tính được chỉ định bên trong khối từ giá trị hiện tại thành bất kỳ giá trị nào bạn cung cấp và sẽ thực hiện nó theo thời gian.

Vì vậy, nếu giá trị alpha ban đầu bằng 0, điều này sẽ mờ dần trong nhãn trên 2 giây. Nếu các giá trị ban đầu đã là 1.0, bạn sẽ không thấy bất kỳ hiệu ứng nào cả.

Dưới mui xe, UIView sẽ quan tâm đến việc tìm ra số lượng khung hình hoạt ảnh mà thay đổi cần phải thực hiện.

Bạn cũng có thể thay đổi tốc độ thay đổi diễn ra bằng cách chỉ định đường cong giảm bớt là UIViewAnimationOption. Một lần nữa, UIView xử lý việc tweening cho bạn.

Các vấn đề liên quan