Create an endless animation with pop?

2019-09-10 03:10发布

问题:

When using the Coreanimation framework I can set an animation to repeat. I want to set a button to an "attract attention" mode which should make him grow and shrink by a small amount to get the users attention.

I already chained the grow and shrink animations via completion blocks. The question is if and how I can start the first animation from the second animation's completion block.

I do get the following warning which does make sense. What is an elegant solution to this problem? I'm not a fan of creating timers for stuff like this.

Capturing 'scaleAnimation' strongly in this block is likely to lead to a retain cycle

- (void)attractAttention:(BOOL)flag{
    _attractAttention = flag;
    float resizeValue = 1.2f;

        // Grow animation
    POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
    scaleAnimation.fromValue  = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)];
    scaleAnimation.toValue  = [NSValue valueWithCGSize:CGSizeMake(resizeValue, resizeValue)];
    scaleAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
            // Grow animation done
        POPSpringAnimation *scaleAnimationDown = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
        scaleAnimationDown.fromValue  = [NSValue valueWithCGSize:CGSizeMake(resizeValue, resizeValue)];
        scaleAnimationDown.toValue  = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)];

        scaleAnimationDown.completionBlock = ^(POPAnimation *anim, BOOL finished) {
                // Shrink animation done
            if (_attractAttention) {
                [self.layer pop_addAnimation:scaleAnimation forKey:@"scaleUpAnimation"];
            }
        };

        [self.layer pop_addAnimation:scaleAnimationDown forKey:@"scaleDownAnimation"];
    };

    [self.layer pop_addAnimation:scaleAnimation forKey:@"scaleUpAnimation"];
}

Edit:

I also tried to create a weak reference of the animation. This removes the error, but the animations do not work anymore:

__weak typeof(scaleAnimation) weakAnimation = scaleAnimation;

回答1:

You can also use the properties autoreveres and repeatCount to achieve the same result without use blocks. It reduces the complexity:

POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
scaleAnimation.toValue = [NSValue valueWithCGSize:CGSizeMake(0.5, 0.5)];
scaleAnimation.springBounciness = 0.f;
scaleAnimation.autoreverses = YES;
scaleAnimation.repeatCount=HUGE_VALF;
[layer pop_addAnimation:scaleAnimation forKey:@"scale"];

Even better, if you check this class https://github.com/facebook/pop/blob/master/pop/POPAnimation.h you will see there is a repeatForever property, so you could replace repeatCount by it:

scaleAnimation.repeatForever=YES;


回答2:

Edited: Do not use this solution. The POP framework has been updated with a “repeat” flag. It was not available when I first encountered this problem.


I solved it by a very easy work around:

- (void)attractAttention:(BOOL)flag{
    _attractAttention = flag;
    if (_attractAttention){
        [self animatePop];
    }
}


- (void)animatePop{
    float resizeValue = 1.2f;

        // Grow animation
    POPSpringAnimation *scaleAnimation = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];

    scaleAnimation.fromValue  = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)];
    scaleAnimation.toValue  = [NSValue valueWithCGSize:CGSizeMake(resizeValue, resizeValue)];
    scaleAnimation.completionBlock = ^(POPAnimation *anim, BOOL finished) {
            // Grow animation done
        POPSpringAnimation *scaleAnimationDown = [POPSpringAnimation animationWithPropertyNamed:kPOPLayerScaleXY];
        scaleAnimationDown.fromValue  = [NSValue valueWithCGSize:CGSizeMake(resizeValue, resizeValue)];
        scaleAnimationDown.toValue  = [NSValue valueWithCGSize:CGSizeMake(1.0f, 1.0f)];

        scaleAnimationDown.completionBlock = ^(POPAnimation *anim, BOOL finished) {
                // Shrink animation done
            if (_attractAttention) {
                [self animatePop];
            }
        };

        [self.layer pop_addAnimation:scaleAnimationDown forKey:@"scaleDownAnimation"];
    };

    [self.layer pop_addAnimation:scaleAnimation forKey:@"scaleUpAnimation"];
}