2010-01-04 28 views
10

Tôi muốn tạo hoạt ảnh với một số khung hình chính. Tôi muốn lớp của tôi (một nút trong trường hợp này) để quy mô lên đến 1,5 sau đó xuống 0,5 sau đó lên đến 1,2 sau đó xuống 0,8 sau đó 1,0.Làm thế nào để bạn CAKeyframeHình thức cân bằng?

Tôi cũng muốn EaseIn và EaseOut của mỗi khung hình chính.

Như bạn có thể hình dung, điều này sẽ tạo ra hiệu ứng Springy/Bounce ngay tại chỗ.

Trong các phần khác của ứng dụng của tôi, tôi đã sử dụng CAKeyframeAnimation như thế này (xem mã bên dưới). Điều này tạo ra một hình ảnh động tương tự nhưng cho vị trí x và y.

Tôi có thể điều chỉnh mã bên dưới để ảnh hưởng đến tỷ lệ thay vì vị trí không?

Cảm ơn bạn trước!

- (CAAnimation*)monInAnimation { 
CGMutablePathRef path = CGPathCreateMutable(); 
CGPathMoveToPoint(path,NULL,113,320); 
CGPathAddLineToPoint(path, NULL, 113.5, 283); 
CGPathAddLineToPoint(path, NULL, 113.5, 179); 
CGPathAddLineToPoint(path, NULL, 113.5, 207); 
CGPathAddLineToPoint(path, NULL, 113.5, 187); 
CGPathAddLineToPoint(path, NULL, 113.5, 199); 
CGPathAddLineToPoint(path, NULL, 113.5, 193); 
CGPathAddLineToPoint(path, NULL, 113.5, 195); 
CGPathAddLineToPoint(path, NULL, 113.5, 194); 

CAKeyframeAnimation * 
animation = [CAKeyframeAnimation 
      animationWithKeyPath:@"position"]; 

[animation setPath:path]; 
[animation setDuration:1.5]; 
[animation setCalculationMode:kCAAnimationLinear]; 
NSArray *arr = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], 
[NSNumber numberWithFloat:0.12], 
[NSNumber numberWithFloat:0.24], 
[NSNumber numberWithFloat:0.36], 
[NSNumber numberWithFloat:0.48], 
[NSNumber numberWithFloat:0.60], 
[NSNumber numberWithFloat:0.72], 
[NSNumber numberWithFloat:0.84], 
[NSNumber numberWithFloat:1.0],nil]; 

[animation setKeyTimes:arr]; 
[animation setTimingFunctions:[NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
           [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], nil]]; 
//[animation setAutoreverses:YES]; 
CFRelease(path); 
return animation; 

}

- (void)monBtnIn { 

[monButton.layer setPosition:CGPointMake(113.5,194)]; 
[monButton.layer addAnimation:[self monInAnimation] 
        forKey:@"position"]; 

}

Trả lời

27

Hai giải pháp thay thế cho bạn:

Đầu tiên, bạn cũng có thể tạo hoạt ảnh biến đổi.

Sử dụng mã của Brad, nhưng sử dụng @ "transform" cho đường phím. Ưu điểm chính là rằng bạn không cần phải tính toán khung hình thực tế, nhưng thay vì cung cấp một yếu tố đơn giản rộng:

Objective-C:

CAKeyframeAnimation *boundsOvershootAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform"]; 

CATransform3D startingScale = CATransform3DScale (layer.transform, 0, 0, 0); 
CATransform3D overshootScale = CATransform3DScale (layer.transform, 1.2, 1.2, 1.0); 
CATransform3D undershootScale = CATransform3DScale (layer.transform, 0.9, 0.9, 1.0); 
CATransform3D endingScale = layer.transform; 

NSArray *boundsValues = [NSArray arrayWithObjects:[NSValue valueWithCATransform3D:startingScale], 
                [NSValue valueWithCATransform3D:overshootScale], 
                [NSValue valueWithCATransform3D:undershootScale], 
                [NSValue valueWithCATransform3D:endingScale], nil]; 
[boundsOvershootAnimation setValues:boundsValues]; 

NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f], 
        [NSNumber numberWithFloat:0.5f], 
        [NSNumber numberWithFloat:0.9f], 
        [NSNumber numberWithFloat:1.0f], nil];  
[boundsOvershootAnimation setKeyTimes:times]; 


NSArray *timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          nil]; 
[boundsOvershootAnimation setTimingFunctions:timingFunctions]; 
boundsOvershootAnimation.fillMode = kCAFillModeForwards; 
boundsOvershootAnimation.removedOnCompletion = NO; 

Swift 4:

let boundsOvershootAnimation = CAKeyframeAnimation(keyPath: "transform") 

let startingScale = CATransform3DScale(layer.transform, 0, 0, 0) 
let overshootScale = CATransform3DScale(layer.transform, 1.2, 1.2, 1.0) 
let undershootScale = CATransform3DScale(layer.transform, 0.9, 0.9, 1.0) 
let endingScale = layer.transform 

boundsOvershootAnimation.values = [startingScale, overshootScale, undershootScale, endingScale] 

boundsOvershootAnimation.keyTimes = [0.0, 0.5, 0.9, 1.0].map { NSNumber(value: $0) } 

boundsOvershootAnimation.timingFunctions = [ 
    CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseOut), 
    CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut), 
    CAMediaTimingFunction(name:kCAMediaTimingFunctionEaseInEaseOut) 
] 

boundsOvershootAnimation.fillMode = kCAFillModeForwards 
boundsOvershootAnimation.isRemovedOnCompletion = false 

Thứ hai và dễ dàng hơn, là sử dụng FTUtils, một trình bao bọc mã nguồn mở cho hoạt ảnh lõi. Nó bao gồm một hình ảnh hoạt hình "xuân".

Bạn có thể nhận được nó tại địa chỉ: http://github.com/neror/ftutils

+1

Công trình này tuyệt vời ... Cảm ơn bạn. Tôi đã thêm một .duration ngươi. Tôi sẽ kiểm tra FTUtilis - Cảm ơn. – Jonathan

+2

Bạn chỉ có thể sử dụng số bằng cách sử dụng Keypath là "transform.scale". Phải không? –

4

Tôi không biết nếu bạn có thể sử dụng một CAKeyframeAnimation cho hiệu ứng động quy mô của một UIView, nhưng bạn có thể làm điều đó với một CABasicAnimation và thiết lập Các thuộc tính fromValue và toValue và sử dụng để tạo hoạt ảnh cho thuộc tính biến đổi:

- (CAAnimation*)monInAnimation 
{ 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform"]; 
    animation.fromValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.0, 1.0, 1.0)]; 
    animation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(3.0, 3.0, 3.0)]; 
    [animation setDuration:1.5]; 
    [animation setAutoreverses:YES]; 
    return animation; 
} 

- (IBAction)monBtnIn 
{ 
    [monButton.layer addAnimation:[self monInAnimation] forKey:@"transform"]; 
} 
+1

Cảm ơn bạn akosma! Tôi đã thử cách chia tỷ lệ đó nhưng tôi không thể tìm ra cách thêm nhiều hơn 2 khung hình chính. Với 'setAutoreverses' nó đi từ A đến B sau đó quay lại A. Tôi muốn đi từ A đến B tới C tới D. bạn có biết nếu bạn có thể thêm nhiều hơn 'fromValues' và 'ToValues' không? Cảm ơn – Jonathan

+0

Hãy xem lớp CAAnimationGroup. Nó kế thừa từ CAAnimation, và với nó, bạn có thể "chuỗi" các CABasicAnimations riêng lẻ, mỗi cái có giá trị riêng từValue và toValue. Đây có phải là những gì bạn đang tìm kiếm không? –

+0

Đầu tiên, tôi đã kiểm tra các tài liệu và có vẻ như các hoạt ảnh trong nhóm CAAnimationGroup được chạy đồng thời, không phải sau lần khác. Rất tiếc. Bạn nên đặt đại biểu cho hoạt ảnh của bạn, và sau đó bắt đầu một hình ảnh động mới khi hình ảnh trước đó đã kết thúc. –

8

R ather hơn là thiết lập đường dẫn của CAKeyframeAnimation, bạn sẽ muốn tự thiết lập các khung hình chính. Tôi đã tạo một "cửa sổ pop-in" hiệu ứng trước bởi hiệu ứng động kích thước của các giới hạn của một lớp:

CAKeyframeAnimation *boundsOvershootAnimation = [CAKeyframeAnimation animationWithKeyPath:@"bounds.size"]; 
CGSize startingSize = CGSizeZero; 
CGSize overshootSize = CGSizeMake(targetSize.width * (1.0f + POPINOVERSHOOTPERCENTAGE), targetSize.height * (1.0f + POPINOVERSHOOTPERCENTAGE)); 
CGSize undershootSize = CGSizeMake(targetSize.width * (1.0f - POPINOVERSHOOTPERCENTAGE), targetSize.height * (1.0f - POPINOVERSHOOTPERCENTAGE)); 
NSArray *boundsValues = [NSArray arrayWithObjects:[NSValue valueWithCGSize:startingSize], 
         [NSValue valueWithCGSize:overshootSize], 
         [NSValue valueWithCGSize:undershootSize], 
         [NSValue valueWithCGSize:targetSize], nil]; 
[boundsOvershootAnimation setValues:boundsValues]; 

NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0f], 
        [NSNumber numberWithFloat:0.5f], 
        [NSNumber numberWithFloat:0.9f], 
        [NSNumber numberWithFloat:1.0f], nil];  
[boundsOvershootAnimation setKeyTimes:times]; 


NSArray *timingFunctions = [NSArray arrayWithObjects:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], 
          nil]; 
[boundsOvershootAnimation setTimingFunctions:timingFunctions]; 
boundsOvershootAnimation.fillMode = kCAFillModeForwards; 
boundsOvershootAnimation.removedOnCompletion = NO; 

nơi POPINOVERSHOOTPERCENTAGE là phần mà tôi muốn để vượt qua kích thước mục tiêu của lớp.

+0

Cảm ơn Brad. Đây chính xác là loại kiểm soát mà tôi theo đuổi. – Jonathan

12

transform.scale, bất cứ ai?

let anim = CAKeyframeAnimation(keyPath: "transform.scale") 
anim.values = [0, 1, 0, 1, 0, 1, 0] 
anim.duration = 4.0 

smallView.layer.addAnimation(anim, forKey: "what") 

Hoàn toàn không liên quan, nếu bạn đang gonna sử dụng phao trong mảng giá trị, bạn phải thêm họ như NSNumbers, nếu không họ sẽ chỉ kết thúc như là 0s!

anim.values = [0.0, 1.2, 0.9, 1.0].map { NSNumber(double: $0) } 
+0

Tôi đã sử dụng "chuyển đổi", nhưng điều đó gây ra vấn đề với 'rotationMode = kCAAnimationRotateAuto'. Sử dụng "transform.scale" cũng làm cho các khai báo giá trị đơn giản hơn. Cảm ơn nhiều. – Henrik

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