How to flash a button on UI thread?

自作多情 提交于 2019-12-08 04:32:07

问题


I have a button on my UI that I would like to flash (turn on and then off again) every 800ms, once the button has been pressed. I do that with the following code:

- (void)flickEmergencyButton {
  // Check whether an emergency is in progress...
  if (model.emergencyInProgress) {
    // ...and if so, flick the state
    self.emergencyButton.selected = !self.emergencyButton.selected;

    // Make this method be called again in 800ms
    [self performSelector:@selector(flickEmergencyButton) withObject:nil afterDelay:0.8];
  } else {
    // ...otherwise, turn the button off
    self.emergencyButton.selected = NO;
  }
}

...which works really well, except: There is a UIScrollView on the UI as well and while the user has his finger down on it and is scrolling around, the button freezes. While I completely understand why that is, I am not sure what to do about it.

The performSelector:withObject:afterDelay message schedules the message to be send on the current thread, which is the main thread, ie. the UI tread and hence does not get to process the message until all other UI activity has come to an end. Correct? But I need to do this on the UI thread as I cannot select/un-select the button on any other thread, right? So what is the solution here?


回答1:


I would recommend using Core Animation. Try something like this:

-(void) flash{
    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:0.3f];
    [UIView setAnimationCurve:UIViewAnimationCurveLinear];

    if( emergency ){       
        // Start flashing
        [UIView setAnimationRepeatCount:1000];
        [UIView setAnimationRepeatAutoreverses:YES];

        [btn setAlpha:0.0f];        
    }else{
        // Stop flashing
        [UIView setAnimationBeginsFromCurrentState:YES];
        [UIView setAnimationRepeatCount:1];

        [btn setAlpha:1.0f];        
    }
    emergency = !emergency;
    [UIView commitAnimations];
}

Where btn is declared as

@property(nonatomic, retain) IBOutlet UIButton *btn;

and emergency is a simple BOOL variable.

Call flash to start and to stop the animation.

In this example we animate the alpha attribute for simplicity, but you can do the same with the button backcolor, as Sam said in his answer, or whatever attribute you like.

Hope it helps.

UPDATE:

Regarding making the transition between two images, try calling imageFlash instead of flash:

-(void) imageFlash{

    CABasicAnimation *imageAnimation = [CABasicAnimation animationWithKeyPath:@"contents"];
    [btn setImage:normalState forState:UIControlStateNormal];

    if( emergency ){        
        imageAnimation.duration = 0.5f;
        imageAnimation.repeatCount = 1000;
    }else{
        imageAnimation.repeatCount = 1;
    }

    imageAnimation.fromValue = (id)normalState.CGImage;
    imageAnimation.toValue = (id)emergencyState.CGImage;    
    [btn.imageView.layer addAnimation:imageAnimation forKey:@"animateContents"];    
    [btn setImage:normalState forState:UIControlStateNormal]; // Depending on what image you want after the animation.

    emergency = !emergency;
}

Where normalState and emergencyState are the images you want to use:

Declared as:

UIImage *normalState;
UIImage *emergencyState;

Assigning the images:

normalState = [UIImage imageNamed:@"normal.png"];
emergencyState = [UIImage imageNamed:@"alert.png"];

Good luck!




回答2:


While this feels like a job for CoreAnimation (perhaps animating the backgroundColor of a custom UIControl) you could accomplish this with an NSTimer running in the appropriate run loop mode.

e.x.

NSTimer *timer = [NSTimer timerWithTimeInterval:0.8f target:self selector:@selector(flicker:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

and when you want to stop animation:

[timer invalidate], timer = nil;
button.selected = NO;

By adding the timer to all NSRunLoopCommonModes, you not only add it to the default run loop mode but the mode it is in while user interaction is being continuously processed (UITrackingRunLoopMode.)

Apple's docs give a more thorough explanation of run loop modes and run loops in general.



来源:https://stackoverflow.com/questions/6893181/how-to-flash-a-button-on-ui-thread

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!