2010-07-19 40 views
7

Tôi đã cố gắng hiểu những gì là sai với hoạt hình của tôi và tôi vẫn chưa tìm ra. Tôi nghĩ rằng nó nên được thực sự thẳng về phía trước, nhưng có lẽ một cái gì đó tôi đang mất tích, ngay cả sau khi đọc rất nhiều ví dụ và tài liệu hướng dẫn.CABasicAnimation không làm động sản tài sản của tôi

Vấn đề của tôi ban đầu hình thành một thực tế là trên iPhone, bạn không thể thay đổi kích thước các lớp tự động (với chế độ xem). Tài liệu nói khác, nhưng không có autoresizeMask cho lớp trong SDK. Vì vậy, tôi quyết định thực hiện một cách giải quyết nhỏ và làm sinh động lớp mình.

Tôi có đoạn mã đơn giản này nên làm một hoạt ảnh thay đổi kích thước đơn giản. Các giá trị là tốt và tôi thậm chí thiết lập các đại biểu để theo dõi nếu các hình ảnh động bắt đầu/kết thúc.

// I've got a property named layerImage (which is a CALayer) 
- (void)animateTestWithFrame:(CGRect)value { 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"layerImage.frame"]; 
    animation.duration = 1; 
    animation.fromValue = [NSValue valueWithCGRect:self.frame]; 
    animation.toValue = [NSValue valueWithCGRect:value]; 
    animation.removedOnCompletion = YES; 
    animation.delegate = self; 

    [self.layer addAnimation:animation forKey:@"layerImage.frame"]; 
} 

Vì vậy, có ý tưởng nào không? (Quan điểm này có chứa mã là subview của một subview của cửa sổ nếu có thể làm cho một sự khác biệt)

--- EDIT ---

Dường như khung mà không animatable qua CABasicAnimation và tên thuộc tính "frame". Khi sử dụng giới hạn, tôi đã có một số kết quả lạ, nhưng ít nhất tôi đang nhận được một cái gì đó. Sẽ tiếp tục điều tra về điều này.

Trả lời

26

Vì vậy, tốt là bạn đã tìm ra những điều ở đây, nhưng câu trả lời cho câu hỏi của riêng bạn có một số điểm không chính xác. Hãy để tôi sửa một vài điều sau:

Thuộc tính khung có thể là hoạt ảnh - không có hoạt ảnh rõ ràng. Nếu bạn làm như sau để một lớp khác với lớp gốc của một cái nhìn, khung sẽ động tốt:

[CATransaction begin]; 
[CATransaction setAnimationDuration:2.0f]; 
[animationLayer setFrame:CGRectMake(100.0f, 100.0f, 100.0f, 100.0f)]; 
[CATransaction commit]; 

Hãy nhớ rằng thiết lập một tài sản trên một lớp sẽ động mà thay đổi sở hữu theo mặc định. Trong thực tế, bạn phải vô hiệu hóa hình ảnh động trên một thay đổi tài sản nếu bạn không muốn nó hoạt hình. (Tất nhiên điều này chỉ đúng nếu bạn đang làm động một lớp khác với lớp gốc của chế độ xem.) Bạn chính xác trong hoạt ảnh cả vị trí và giới hạn nếu bạn cần sử dụng hoạt ảnh rõ ràng.

Bạn thể animate khung trên một UIView sử dụng hình ảnh động ngầm:

[UIView beginAnimations:nil context:NULL]; 
[UIView setAnimationDuration:3.0f]; 
[[self view] setFrame:CGRectMake(45.0f, 45.0f, 100.0f, 100.0f)]; 
[UIView commitAnimations]; 

này sẽ động từ khung hiện hành của view (giới hạn và chức vụ) để x = 45,0, y = 45,0, w = 100,0 , h = 100.0.

Dường như bạn cũng có thể hiểu sai sự khác biệt giữa hoạt ảnh và lớp. Bạn thêm hoạt ảnh vào các lớp, nhưng thêm hoạt ảnh vào một lớp sẽ không tự động đặt thuộc tính mà bạn đang tạo hoạt ảnh.

CALayers là các đối tượng mô hình. Chúng chứa thông tin về lớp cuối cùng được đưa ra màn hình. Bạn phải đặt thuộc tính của lớp nếu bạn muốn thuộc tính đó thực sự có giá trị đó. Nếu bạn chỉ đơn giản là tạo hiệu ứng cho thuộc tính, nó sẽ chỉ là một biểu diễn trực quan và không thực tế - đó là lý do tại sao giá trị này quay lại giá trị ban đầu của lớp vì bạn chưa bao giờ thực sự thay đổi nó.

Điều này dẫn tôi đến điểm tiếp theo. Bạn nói:

Sử dụng "animation.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards;" để đảm bảo rằng các giá trị không được đặt lại ở cuối của hoạt ảnh

Điều này là không chính xác. Hai giá trị này đơn giản khiến cho hoạt ảnh vẫn ở vị trí cuối cùng của nó là trực quan, tuy nhiên, giá trị thực của lớp không thay đổi. Chúng vẫn là giá trị chính xác giống như khi bạn bắt đầu hoạt ảnh. Nói chung (với một vài ngoại lệ), bạn không muốn sử dụng hai tham số này vì chúng là chỉ hiển thị. Điều bạn muốn thực sự là đặt giá trị lớp cho thuộc tính bạn đang tạo hoạt ảnh.

Giả sử, ví dụ: bạn muốn tạo hiệu ứng cho vị trí của lớp bằng cách sử dụng hoạt ảnh rõ ràng. Đây là mã bạn muốn:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"]; 
[animation setFromValue:[NSValue valueWithCGPoint:CGPointMake(70.0f, 70.0f)]]; 
[animation setToValue:[NSValue valueWithCGPoint:CGPointMake(150.0f, 150.0f)]]; 
[animation setDuration:2.0f]; 

// Actually set the position on the *layer* that you want it to be 
// when the animation finishes. 
[animationLayer setPosition:CGPointMake(150.0f, 150.0f)]; 

// Add the animation for the position key to ensure that you 
// override the animation for position changes with your animation. 
[animationLayer addAnimation:animation forKey:@"position"]; 

Bạn cũng có thể muốn xem xét nhóm hoạt hình. Với nhóm hoạt ảnh, bạn có thể nhóm nhiều hoạt ảnh lại với nhau và sau đó kiểm soát cách chúng liên quan với nhau.Trong trường hợp của bạn, khoảng thời gian giới hạn và ảnh động của bạn giống nhau và vì vậy những gì bạn đang cố gắng làm sẽ hoạt động tốt mà không có nhóm, nhưng nếu bạn muốn bù lại phần bắt đầu của hoạt ảnh, ví dụ bạn không muốn vị trí đó hoạt ảnh để bắt đầu cho đến khi một hoặc hai giây vào hoạt ảnh khung, bạn có thể cắt xén chúng bằng cách đặt giá trị bắt đầu giá trị thời gian bắt đầu là của hoạt ảnh vị trí.

Cuối cùng, tôi sẽ tò mò muốn biết lý do tại sao bạn không thể sử dụng các hoạt ảnh ngầm có sẵn trên UIView. Tôi sử dụng chúng trong phần lớn mã Core Animation mà tôi viết và không thể thấy tại sao điều này sẽ không hiệu quả cho tình huống của bạn.

Trân trọng.

+0

Cảm ơn Matt đã giải thích. Nhưng đối với vấn đề hoạt hình UIView, nó chỉ liên quan đến lớp của tôi. Thông thường, tôi không có vấn đề với hoạt hình bằng cách sử dụng UIView, nhưng trong trường hợp của tôi nó đã gây ra hành vi kỳ lạ. Thay đổi kích thước khung xem không đổi kích thước lớp trên iPhone (vì không có cơ chế tự động trên iPhone, chỉ dành cho chế độ xem và xem phụ). Vì vậy, bạn phải làm điều đó "bằng tay". – Sauleil

+0

Câu trả lời hay! Rất chi tiết. Tôi sẽ cho bạn 2 điểm trong trường hợp tôi có thể. – Soberman

3

Đường dẫn chính chỉ nên là đường dẫn chính của thuộc tính chứ không phải tên của đối tượng.

Sử dụng này

[CABasicAnimation animationWithKeyPath:@"frame"] 

thay vì điều này

[CABasicAnimation animationWithKeyPath:@"layerImage.frame"] 

Và chỉ BTW, khi bạn thêm hình ảnh động vào một lớp, các doen't chìa khóa có nghĩa là tài sản quan trọng để animate. Chỉ cần chìa khóa (tên) mà bạn muốn hoạt ảnh này có (điều này đề cập đến dòng cuối cùng mã của bạn)

+0

ok cho khung hình, nhưng CABasicAnimation biết lớp nào để tạo hiệu ứng cho thuộc tính đó? điều đó có nghĩa là tôi phải làm [layerImage addAnimation: animation ...]. (Thử nó và không hoạt động) – Sauleil

+0

Nếu bạn đang làm hoạt hình trên một đối tượng khác với bản thân (trong phương thức đó), chỉ cần sử dụng [self.layerImage.layer addAnimation: animation ...] – tadejsv

+0

Một điều nữa: Tôi không hiểu tại sao bạn đang sử dụng CABasicAnimation tại đây. Hoạt ảnh của UIView sẽ làm. – tadejsv

1

Vì vậy, giải pháp là tạo hiệu ứng "@ bounds" và @ "position" của lớp vì khung không hoạt hình trên iPhone. Tôi đã mất một thời gian để hiểu rằng vị trí là trung tâm của lớp và sự thay đổi kích thước của các giới hạn đã kéo dài từ trung tâm, nhưng đó là phần dễ dàng.

Vì vậy, những gì tôi đã làm trong sơ yếu lý lịch là:

  1. Trong setFrame, tạo 2 hình ảnh động với các giới hạn và tài sản vị trí.
  2. Sử dụng "hoạt hình.removedOnCompletion = NO; animation.fillMode = kCAFillModeForwards;" để đảm bảo rằng các giá trị không được đặt lại ở cuối hoạt ảnh
  3. Đăng ký đại biểu cho chính mình để thực hiện "animationDidStop: finished:". Có vẻ như bạn vẫn cần thiết lập các giá trị: "layerImage.bounds = [animation.toValue CGRectValue]; layerImage.position = [animation.toValue CGPointValue];".

Tôi không thể sử dụng hệ thống hoạt ảnh UIView trực tiếp vì nó không làm những gì tôi muốn trên các lớp.

Cảm ơn tadej5553 vì đã chỉ cho tôi vấn đề về lớp mà tôi đã có với "addAnimation". Vì vậy, đây là mã cho những người muốn xem nó trông như thế nào.

- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag { 
    CABasicAnimation *animation = (CABasicAnimation*)anim; 

    if ([animation.keyPath isEqualToString:@"bounds"]) { 
     layerImage.bounds = [animation.toValue CGRectValue]; 
    } else if ([animation.keyPath isEqualToString:@"position"]) { 
     layerImage.position = [animation.toValue CGPointValue]; 
    } 
} 

- (void)setFrame:(CGRect)value { 
    CGRect bounds = CGRectMake(0, 0, value.size.width, value.size.height); 

    if ([UIView isAnimationStarted]) { 
     // animate the bounds 
     CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"]; 
     animation.duration = [UIView animationDuration]; 
     animation.fromValue = [NSValue valueWithCGRect:layerImage.bounds]; 
     animation.toValue = [NSValue valueWithCGRect:bounds]; 
     animation.removedOnCompletion = NO; 
     animation.fillMode = kCAFillModeForwards; 
     animation.timingFunction = [UIView animationFunction]; 
     animation.delegate = self; 
     [layerImage addAnimation:animation forKey:@"BoundsAnimation"]; 

     // animate the position so it stays at 0, 0 of the frame. 
     animation = [CABasicAnimation animationWithKeyPath:@"position"]; 
     animation.duration = [UIView animationDuration]; 
     animation.fromValue = [NSValue valueWithCGPoint:layerImage.position]; 
     animation.toValue = [NSValue valueWithCGPoint:CGPointMake(bounds.size.width/2, bounds.size.height/2)]; 
     animation.removedOnCompletion = NO; 
     animation.fillMode = kCAFillModeForwards; 
     animation.timingFunction = [UIView animationFunction]; 
     animation.delegate = self; 
     [layerImage addAnimation:animation forKey:@"PositionAnimation"]; 
    } else { 
     layerImage.frame = bounds; 
    } 

    [super setFrame:value]; 
} 
Các vấn đề liên quan