UIButton flashing animation

14,254

Solution 1

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];
    }];
}

Solution 2

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;
}];

Solution 3

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];

Solution 4

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?

Solution 5

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"];
}
Share:
14,254
Alessandro
Author by

Alessandro

Updated on July 21, 2022

Comments

  • Alessandro
    Alessandro almost 2 years

    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 UIButton continuously. I instead was thinking about some kind of flashing animation to alert the user he has to press the button. The only approach to the problem I can think of is by changing the alpha constantly using:

    [self setAlpha:0.5]; 
    

    ...but it won't be as visible as a flashing button.