There's a lot of details to get right, but the general idea is to create a non-repeating animation that is removed on completion, and then use the animationDidStop
delegate method to restart the animation.
The first item of business is to declare some properties
@property (weak, nonatomic) IBOutlet UIImageView *orangeView2;
@property (nonatomic) bool pulseActive;
@property (strong, nonatomic) CAKeyframeAnimation *pulseAnimation;
The first property is the view that will be animated, the second keeps track of whether the animation is enabled, and the last is the actual animation (stored in property so that we only have to instantiate it once).
Next, we'll use lazy instantiation to create the animation object
- (CAKeyframeAnimation *)pulseAnimation
{
if ( !_pulseAnimation )
{
_pulseAnimation = [CAKeyframeAnimation animationWithKeyPath:@"opacity"];
_pulseAnimation.values = @[ @0.0f, @1.0f, @0.0f ];
_pulseAnimation.duration = 0.5;
_pulseAnimation.delegate = self;
[_pulseAnimation setValue:@"PulseAnimation" forKey:@"AnimationIdentifier"];
}
return( _pulseAnimation );
}
The important bits here are
- the animation does not repeat (by default)
- the animation is
removedOnCompletion
(by default)
- the
delegate
is set to self
so that the animationDidStop
method
will be called
- the animation is given an identifier using
setValue:forKey:
That last item is only needed if multiple animations are using the same delegate, since in that case, you'll need a way to determine which animation called animationDidStop
. The strings passed to forKey
and setValue
are arbitrary, and are stored in a dictionary in the animation object.
Ok, so now we need to implement animationDidStop
. The implementation checks the pulseActive
property and restarts the animation if necessary (after checking the identity of the animation).
- (void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
NSString *animationIdentifier = [animation valueForKey:@"AnimationIdentifier"];
if ( [animationIdentifier isEqualToString:@"PulseAnimation"] )
{
if ( self.pulseActive )
[self.orangeView2.layer addAnimation:self.pulseAnimation forKey:@"pulsate"];
}
}
All that's left is to start and stop the animation. For example, a button that toggles the animation
- (IBAction)pulseButtonPressed
{
if ( !self.pulseActive )
{
self.pulseActive = YES;
[self.orangeView2.layer addAnimation:[self pulseAnimation] forKey:@"pulsate"];
}
else
{
self.pulseActive = NO;
}
}