2008-11-17 46 views
46

Tôi tự hỏi nơi các cuộc gọi lại là (hoặc nếu có bất kỳ điều gì) cho hoạt ảnh trong một CALayer. Cụ thể, đối hình ảnh động ngụ ý như thay đổi khung hình, vị trí, vv Trong một UIView, bạn có thể làm một cái gì đó như thế này:Hoạt ảnh kết thúc cuộc gọi lại cho CALayer?

[UIView beginAnimations:@"SlideOut" context:nil]; 
[UIView setAnimationDuration:.3]; 
[UIView setAnimationDelegate:self]; 
[UIView setAnimationDidStopSelector:@selector(animateOut:finished:context:)]; 
CGRect frame = self.frame; 
frame.origin.y = 480; 
self.frame = frame; 
[UIView commitAnimations]; 

Cụ thể, setAnimationDidStopSelector là những gì tôi muốn cho một hình ảnh động trong một CALayer. Có cái gì như thế không?

TIA.

+0

Đối với bất cứ ai googling ở đây, tôi đã đưa vào một câu trả lời hiện đại này vô cùng câu hỏi cũ! : O Tìm kiếm xuống "2017 ..." – Fattie

Trả lời

50

Tôi đã trả lời câu hỏi của riêng mình. Bạn cần phải thêm một phim hoạt hình sử dụng CABasicAnimation như vậy:

CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"frame"]; 
anim.fromValue = [NSValue valueWithCGRect:layer.frame]; 
anim.toValue = [NSValue valueWithCGRect:frame]; 
anim.delegate = self; 
[layer addAnimation:anim forKey:@"frame"]; 

Và thực hiện các phương pháp đại biểu animationDidStop:finished: và bạn sẽ được tốt để đi. Cảm ơn lòng tốt chức năng này tồn tại! : D

+2

Câu trả lời này hữu ích cho thông tin về đại biểu, nhưng nó có một lỗ hổng lớn - bạn không thể tạo hiệu ứng "khung" vì nó là thuộc tính có nguồn gốc. http://developer.apple.com/library/mac/#qa/qa2008/qa1620.html – Michal

0

Bạn có thể đặt tên của một hình động nhất định khi thiết lập đối tượng CAAnimation. Trong animationDiStop: đã hoàn thành, chỉ cần so sánh tên của đối tượngAnAnation được cung cấp để thực hiện chức năng cụ thể của bạn dựa trên hoạt ảnh.

+1

Không có thuộc tính tên? – Andy

104

Bạn có thể sử dụng CATransaction, nó có trình xử lý khối hoàn thành.

[CATransaction begin]; 
CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; 
[pathAnimation setDuration:1]; 
[pathAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];  
[pathAnimation setToValue:[NSNumber numberWithFloat:1.0f]]; 
[CATransaction setCompletionBlock:^{_lastPoint = _currentPoint; _currentPoint = CGPointMake(_lastPoint.x + _wormStepHorizontalValue, _wormStepVerticalValue);}]; 
[_pathLayer addAnimation:pathAnimation forKey:@"strokeEnd"]; 
[CATransaction commit]; 
+15

Lưu ý rằng điều quan trọng là đặt khối hoàn thành TRƯỚC KHI bạn thêm hoạt ảnh vào lớp. – Groot

+0

Điều này không phải lúc nào cũng hữu ích vì bạn cũng được gọi khi bạn xóa hoạt ảnh ngay cả khi không kết thúc. –

8

Chỉ cần một lưu ý cho những ai tìm thấy trang này trên Google: Bạn thực sự có thể hoàn thành công việc bằng cách thiết lập các "đại biểu" tài sản của đối tượng hoạt hình của mình vào đối tượng đó sẽ nhận được thông báo và thực hiện "animationDidStop "phương thức trong tệp .m của đối tượng đó. Tôi chỉ thử nó, và nó hoạt động. Tôi không biết tại sao Joe Blow lại nói đó không phải là cách chính xác.

+0

Đã thử mọi thứ từ removeAllAnimations đến các CAAnimations cụ thể bằng setCompletionBlock và CATransation.begin và cam kết như câu trả lời của user3077725. Đã thử UIView.animateWIthDuration. Đã không hoạt động cho hoạt ảnh alpha và position.x đơn giản. Phương pháp đại biểu là điều duy nhất hoạt động đúng cách – KorinW

44

Đã lãng phí 4 giờ với rác thải này, chỉ để làm mờ dần dần. Lưu ý nhận xét trong mã.

[CATransaction begin]; 
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"]; 
    animation.duration = 0.3; 
    animation.fromValue = [NSNumber numberWithFloat:0.0f]; 
    animation.toValue = [NSNumber numberWithFloat:1.0f]; 
    animation.removedOnCompletion = NO; 
    animation.fillMode = kCAFillModeBoth; 
    /// [box addAnimation:animation forKey:@"j"]; Animation will not work if added here. Need to add this only after the completion block. 

    [CATransaction setCompletionBlock:^{ 

     CABasicAnimation *animation2 = [CABasicAnimation animationWithKeyPath:@"opacity"]; 
     animation2.duration = 0.3; 
     animation2.beginTime = CACurrentMediaTime()+1; 
     animation2.fromValue = [NSNumber numberWithFloat:1.0f]; 
     animation2.toValue = [NSNumber numberWithFloat:0.0f]; 
     animation2.removedOnCompletion = NO; 
     animation2.fillMode = kCAFillModeBoth; 
     [box addAnimation:animation2 forKey:@"k"]; 

    }]; 

    [box addAnimation:animation forKey:@"j"]; 

    [CATransaction commit]; 
+0

Tôi đoán, trong nguyên nhân của bạn, bạn có thể đã sử dụng thuộc tính autoreverse, bởi vì những gì bạn đang làm về cơ bản là đảo ngược hoạt ảnh đầu tiên. – denis631

+0

Câu trả lời này làm tôi cười! Tôi đã hoàn toàn ở đó cố gắng để có được một thứ dường như nhỏ để làm việc trong vài giờ ... ✊ –

29

Dưới đây là một câu trả lời trong Swift 3.0 dựa trên giải pháp bennythemink của:

// Begin the transaction 
    CATransaction.begin() 
    let animation = CABasicAnimation(keyPath: "strokeEnd") 
    animation.duration = duration //duration is the number of seconds 
    animation.fromValue = 0 
    animation.toValue = 1 
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) 
    circleLayer.strokeEnd = 1.0 

    // Callback function 
    CATransaction.setCompletionBlock { 
     print("end animation") 
    } 

    // Do the actual animation and commit the transaction 
    circleLayer.add(animation, forKey: "animateCircle") 
    CATransaction.commit() 
8

Đối với năm 2018 ...

Swift 4.

Trên thực tế bạn cần [weak self] hoặc bạn' thường sẽ sụp đổ.

func animeExample() { 

    CATransaction.begin() 

    let a = CABasicAnimation(keyPath: "fillColor") 
    a.fromValue, duration = ... etc etc 

    CATransaction.setCompletionBlock{ [weak self] in 
     self?.animeExample() 
    } 

    someLayer.add(a, forKey: nil) 
    CATransaction.commit() 
} 

Trong ví dụ, nó chỉ tự gọi lại.

Tất nhiên, bạn có thể gọi bất kỳ chức năng nào.


Lưu ý: nếu bạn mới bắt đầu. Điều đáng ghi nhớ là "khóa" (như trong add#forKey) là không thích hợp và hiếm khi được sử dụng. Đặt nó thành không. Nếu vì một số lý do bạn muốn đặt nó, nó là "bất kỳ chuỗi" (nói, biệt danh của bạn). Các keyPath trong các cuộc gọi CABasicAnimation là thực tế "điều bạn đang hoạt hình", nói cách khác nó theo nghĩa đen là một tài sản của lớp (chỉ được viết dưới dạng một chuỗi).

1

Trong Swift 4+ tôi vừa thêm delegate như

class CircleView: UIView,CAAnimationDelegate { 
... 

let animation = CABasicAnimation(keyPath: "strokeEnd") 
animation.delegate = self//Set delegate 

Animation hoàn callback -

func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { 
    print("Animation END") 
    } 
Các vấn đề liên quan