i was playing around with this for a while, too. i wanted to play a small and subtle pulse animation on an object most of the time, but occasionally have a strong and accentuated pulse animation. so i wanted a general purpose pulsating function. the solution i came up with was this:
first, i define all the parameters i want to adjust:
Code:
struct pulseAnimation{
float durationInSeconds;
float expansionFactor;
int numRepetitions;
UIViewAnimationCurve expandCurve;
UIViewAnimationCurve contractCurve;
};
there are some slight differences in how i animate the pulse effect. first of all, i use a numRepetitions variable instead of looping my pulse animations indefinitely. To get something to pulse every second, i'd manually call my pulse function with 1 repetition every second by using an update loop or a timer.
Then, to animate an object, i use:
Code:
// expansion part of a pulse animation
- (void)pulse:(pulseAnimation*)animationData{
// memory management issue: we need to retain a COPY of the //animation info because
// we overwrite some of its data while animating, and because
// the animationInfo could be the address of a local variable! to //encapsulate this,
// we just store a copy of the data as a member variable.
if (animationData)
pulse = *animationData;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:pulse.durationInSeconds];
[UIView setAnimationCurve:pulse.expandCurve];
// scale the object to its expanded size
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(pulse_reverse)];
[startButton setTransform:CGAffineTransformMakeScale(pulse.expansionFactor, pulse.expansionFactor)];
[UIView commitAnimations];
}
// contraction part of a pulse animation. This gets called automatically after the
// expansion part finishes - not intended to be called manually.
- (void)pulse_reverse{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:pulse.durationInSeconds];
[UIView setAnimationCurve:pulse.contractCurve];
// object is at maximum expanded size, so revert back to original size
[startButton setTransform:CGAffineTransformIdentity];
// after doing this contraction, a pulse animation is completed.
// but, we have a feature that allows us to play more than one pulse animation in a row...
--pulse.numRepetitions;
if (pulse.numRepetitions > 0){
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector(pulse:)];
}
[UIView commitAnimations];
}
To use this function, I'd do something like:
Code:
pulseAnimation bigPulse = {
// fill in the data here...
};
[self pulse:&bigPulse];
Note that the above code is in a viewController and the object i'm animating (startButton) is hardcoded. This is definitely not ideal, but since i'm only animating one object, it's good enough for me.
i originally had everything in one big animation function that used the animation name and context, but as always i found that things become much easier if you split your task into specific functions that take as few parameters as possible.