How to identify CAAnimation within the animationDidStop delegate?

后端 未结 10 2135
梦毁少年i
梦毁少年i 2020-11-28 18:26

I had a problem where I had a series of overlapping CATransition / CAAnimation sequences, all of which I needed to perform custom operations when the animations stopped, but

相关标签:
10条回答
  • 2020-11-28 18:45

    For me to check if 2 CABasicAnimation object are the same animation, I use keyPath function to do exactly as that.

    if([animationA keyPath] == [animationB keyPath])

    • There are no need to set KeyPath for CABasicAnimation as it will no longer animate
    0 讨论(0)
  • 2020-11-28 18:46

    The second approach will only work if you explicitly set your animation to not be removed on completion before running it:

    CAAnimation *anim = ...
    anim.removedOnCompletion = NO;
    

    If you fail to do so, your animation will get removed before when it completes, and the callback will not find it in the dictionary.

    0 讨论(0)
  • 2020-11-28 18:53

    I can see mostly objc answers I will make one for swift 2.3 based on the best answer above.

    For a start it will be good to store all those keys on a private struct so it is type safe and changing it in the future won't bring you annoying bugs just because you forgot to change it everywhere in the code:

    private struct AnimationKeys {
        static let animationType = "animationType"
        static let volumeControl = "volumeControl"
        static let throbUp = "throbUp"
    }
    

    As you can see I have changed the names of the variables/animations so it is more clear. Now setting these keys when the animation is created.

    volumeControlAnimation.setValue(AnimationKeys.volumeControl, forKey: AnimationKeys.animationType)
    

    (...)

    throbUpAnimation.setValue(AnimationKeys.throbUp, forKey: AnimationKeys.animationType)
    

    Then finally handling the delegate for when the animation stops

    override func animationDidStop(anim: CAAnimation, finished flag: Bool) {
        if let value = anim.valueForKey(AnimationKeys.animationType) as? String {
            if value == AnimationKeys.volumeControl {
                //Do volumeControl handling
            } else if value == AnimationKeys.throbUp {
                //Do throbUp handling
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-28 18:55

    I like to use setValue:forKey: to keep a reference of the view I'm animating, it's more safe than trying to uniquely identify the animation based on ID because the same kind of animation can be added to different layers.

    These two are equivalent:

    [UIView animateWithDuration: 0.35
                     animations: ^{
                         myLabel.alpha = 0;
                     } completion: ^(BOOL finished) {
                         [myLabel removeFromSuperview];
                     }];
    

    with this one:

    CABasicAnimation *fadeOut = [CABasicAnimation animationWithKeyPath:@"opacity"];
    fadeOut.fromValue = @([myLabel.layer opacity]);
    fadeOut.toValue = @(0.0);
    fadeOut.duration = 0.35;
    fadeOut.fillMode = kCAFillModeForwards;
    [fadeOut setValue:myLabel forKey:@"item"]; // Keep a reference to myLabel
    fadeOut.delegate = self;
    [myLabel.layer addAnimation:fadeOut forKey:@"fadeOut"];
    myLabel.layer.opacity = 0;
    

    and in the delegate method:

    - (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
    {
        id item = [anim valueForKey:@"item"];
    
        if ([item isKindOfClass:[UIView class]])
        {
            // Here you can identify the view by tag, class type 
            // or simply compare it with a member object
    
            [(UIView *)item removeFromSuperview];
        }
    }
    
    0 讨论(0)
  • 2020-11-28 18:57

    All other answers are way too complicated! Why don't you just add your own key to identify the animation?

    This solution is very easy all you need is to add your own key to the animation (animationID in this example)

    Insert this line to identify animation1:

    [myAnimation1 setValue:@"animation1" forKey:@"animationID"];
    

    and this to identify animation2:

    [myAnimation2 setValue:@"animation2" forKey:@"animationID"];
    

    Test it like this:

    - (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
    {
        if([[animation valueForKey:@"animationID"] isEqual:@"animation1"]) {
        //animation is animation1
    
        } else if([[animation valueForKey:@"animationID"] isEqual:@"animation2"]) {
        //animation is animation2
    
        } else {
        //something else
        }
    }
    

    It does not require any instance variables:

    0 讨论(0)
  • 2020-11-28 19:01

    IMHO using Apple's key-value is the elegant way of doing this: it's specifically meant to allow adding application specific data to objects.

    Other much less elegant possibility is to store references to your animation objects and do a pointer comparision to identify them.

    0 讨论(0)
提交回复
热议问题