I was wondering if it was possible to apply a flashing animation to a UIButton. I have searched but only found the code for a pulse animation which changes the size of my UIButt
I did this by creating my own control, subclassing UIControl since Apple doesn't recommend screwing with the view hierarchy of UIButton. I add a background imageView representing the standard background image of the button, and a "glowing" imageView above the background to represent the lit-up state, and toggle its opacity to make it pulse.
I additionally toggle the layer's shadow opacity to make it glow.
Initializing Code:
- (void)TS_commonButtonInit
{
UIImage *shoutoutBackground = [UIImage imageNamed:@"root-navigation-bar-share-button"];
UIImage *shoutoutHighlightedBackground = [UIImage imageNamed:@"root-navigation-bar-share-button-highlighted"];
UIImage *shoutoutPulseImage = [UIImage imageNamed:@"root-navigation-bar-share-button-glowing"];
shoutoutBackground = [shoutoutBackground stretchableImageWithLeftCapWidth:7 topCapHeight:0];
shoutoutHighlightedBackground = [shoutoutHighlightedBackground stretchableImageWithLeftCapWidth:7 topCapHeight:0];
shoutoutPulseImage = [shoutoutPulseImage stretchableImageWithLeftCapWidth:7 topCapHeight:0];
[[self backgroundView] setImage:shoutoutBackground];
[[self backgroundView] setHighlightedImage:shoutoutHighlightedBackground];
[self setGlowingImage:shoutoutPulseImage];
[self setExclusiveTouch:YES];
[self addSubview:[self backgroundView]];
[self addSubview:[self glowingImageView]];
[[self layer] setShadowColor:[[UIColor colorWithHexString:@"ffc521" alpha:1] CGColor]];
[[self layer] setShadowOpacity:0];
[[self layer] setShadowRadius:5];
[[self layer] setShadowOffset:CGSizeMake(0, 0)];
[[self layer] setShadowPath:[[UIBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:6] CGPath]];
}
Pulsing Code:
- (void)pulse:(NSInteger)numberOfTimes
{
CGFloat pulseLength = .8;
[[self glowingImageView] setAlpha:0];
CABasicAnimation *pulseAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
[pulseAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[pulseAnimation setDuration:pulseLength];
[pulseAnimation setRepeatCount:numberOfTimes];
[pulseAnimation setAutoreverses:YES];
[pulseAnimation setFromValue:@(0)];
[pulseAnimation setToValue:@(1)];
[pulseAnimation setRemovedOnCompletion:YES];
[[self layer] setShadowOpacity:0];
CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowOpacity"];
[shadowAnimation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[shadowAnimation setDuration:pulseLength];
[shadowAnimation setRepeatCount:numberOfTimes];
[shadowAnimation setAutoreverses:YES];
[shadowAnimation setFromValue:@(0)];
[shadowAnimation setToValue:@(1)];
[shadowAnimation setRemovedOnCompletion:YES];
[[[self glowingImageView] layer] addAnimation:pulseAnimation forKey:@"opacity"];
[[self layer] addAnimation:shadowAnimation forKey:@"shadowOpacity"];
}
Try this one:
call this method when you want blink/flash the button
blinkTimer=[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(toggleButtonImage:) userInfo:nil repeats:YES];
and write this method
- (void)toggleButtonImage:(NSTimer*)timer
{
if(toggle)
{
[blinkBtn setImage:[UIImage imageNamed:@"ButtonImage.png"] forState: UIControlStateNormal];
}
else
{
[blinkBtn setImage:[UIImage imageNamed:@"ButtonImage1.png"] forState: UIControlStateNormal];
}
toggle = !toggle;
}
in .h write this one
NSTimer *blinkTimer;
BOOL toggle;
and invalidate the timer where you want to stop the flashing/blinking
[blinkTimer invalidate];
Reading all the answers so far I found following solution. It repeats a number of times and does the job for me.
CGFloat oldAlpha = v.alpha;
CGFloat minAlpha = 0.2;
enum UIViewAnimationOptions options = UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionAutoreverse | UIViewAnimationOptionCurveEaseInOut;
[UIView animateWithDuration:.3 delay:0.3 options:options animations:^{
[UIView setAnimationRepeatCount:4];
v.alpha = minAlpha;
}
completion:^(BOOL finished) {
v.alpha = oldAlpha;
}];
Perhaps not the best way, and doesn't really allow you to stop the flashing... but this is simple, works, and does not hinder user interaction:
- (void)viewDidLoad
{
[self flashOn:myButton];
}
- (void)flashOff:(UIView *)v
{
[UIView animateWithDuration:.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^ {
v.alpha = .01; //don't animate alpha to 0, otherwise you won't be able to interact with it
} completion:^(BOOL finished) {
[self flashOn:v];
}];
}
- (void)flashOn:(UIView *)v
{
[UIView animateWithDuration:.05 delay:0 options:UIViewAnimationOptionAllowUserInteraction animations:^ {
v.alpha = 1;
} completion:^(BOOL finished) {
[self flashOff:v];
}];
}
Maybe you could have two different .png files [buttons] that cycle back and forth in a loop, assign the same action to them, and have this kick off whenever a certain condition is met. I'd write the code out but it would likely be full of errors. Have you tried something like that?