93

When I call setTitle on a UIButton, the button flashes in iOS 7. I tried setting myButton.highlighted = NO, but that didn't stop the button from flashing.

[myButton setTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"elapsedLabelKey"] forState:UIControlStateNormal];

myButton.highlighted = NO;

Here is how I set up the timer that updated the titles:

- (void)actionTimer {
    if (myTimer == nil) {

        myTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0
                        target: self
                        selector: @selector(showActivity)
                        userInfo: nil
                        repeats: YES];
    }
}

Here is the method that actually updates the titles:

- (void)showActivity {

    NSString *sym = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];

    if (pauseInterval == nil) {

        // Update clock
        seconds = [[NSDate date] timeIntervalSinceDate:startInterval] - breakTime;

        // Update total earned
        secRate = rate.value / 60 / 60;
        total = secRate * seconds;
        [totalLabel setTitle:[NSString stringWithFormat:@"%@%.4f",sym,total] forState:UIControlStateNormal];

        days = seconds / (60 * 60 * 24);
        seconds -= days * (60 * 60 * 24);
        int hours = seconds / (60 * 60);
        fhours = (float)seconds / (60.0 * 60.0);
        seconds -= hours * (60 * 60);
        int minutes = seconds / 60;
        seconds -= minutes * 60;

        // Update the timer clock
        [elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
FierceMonkey
  • 1,964
  • 1
  • 16
  • 22
  • It shouldn't be flashing. Are you trying to do this on a background thread? – BergQuester Oct 15 '13 at 00:55
  • Yes it's being set in a timer to update the button title every second (which I think create its own thread) – FierceMonkey Oct 15 '13 at 04:47
  • Timers only run on a separate thread if you set them up to do so. Could we see the method where the title gets update and how you set up the timer? – BergQuester Oct 15 '13 at 05:36
  • I added the requested code to the main question – FierceMonkey Oct 15 '13 at 23:30
  • Possible duplicate of [How to stop unwanted UIButton animation on title change?](http://stackoverflow.com/questions/18946490/how-to-stop-unwanted-uibutton-animation-on-title-change) – Cœur Aug 22 '16 at 03:31
  • This answer from G.S.Koti worked for me https://stackoverflow.com/a/35362156/9576580 – Brar Jun 08 '18 at 00:11

9 Answers9

234

Set the button type to UIButtonTypeCustom and it'll stop flashing

Quanlong
  • 24,028
  • 16
  • 69
  • 79
64

A better approach than [UIView setAnimationsEnabled:NO] which may affect other animations is to only disable the specific title animation.

Objective-C:

[UIView performWithoutAnimation:^{
  [myButton setTitle:text forState:UIControlStateNormal];
  [myButton layoutIfNeeded];
}];

Swift:

UIView.performWithoutAnimation { 
    myButton.setTitle(text, for: .normal)
    myButton.layoutIfNeeded()
}
Cœur
  • 37,241
  • 25
  • 195
  • 267
30

*Please note *

when "buttonType" of _button is "UIButtonTypeSystem", below code is invalid

[UIView setAnimationsEnabled:NO];
[_button setTitle:@"title" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

when "buttonType" of _button is "UIButtonTypeCustom", above code is valid.

shede333
  • 1,105
  • 10
  • 7
19

See the responses from How to stop unwanted UIButton animation on title change? :

[UIView setAnimationsEnabled:NO];
[elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];
Community
  • 1
  • 1
Marius
  • 3,589
  • 3
  • 27
  • 30
9

You can simply just make another function for UIButton for easy future usage.

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

That is it!

And just set the title as you would before but replace setTitle with setTitleWithoutAnimation

Daniel Tseng
  • 292
  • 3
  • 8
7

Default "setTitle" behavior is definitely hateful!

My solution is:

[UIView setAnimationsEnabled:NO];
[_button layoutIfNeeded]; 
[_button setTitle:[NSString stringWithFormat:@"what" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

Also, in storyboard, under button's property I uncheck:

  • Reverses On Highlight
  • Highlighted Adjust Image

And check:

  • Disabled Adjust Image

Tested and working on iOS 8 too.

Update - Swift

I suggest you to create your custom button and override setTitle method.

class UnflashingButton: UIButton {
   
    override func setTitle(title: String?, forState state: UIControlState) {
        UIView.setAnimationsEnabled(false)
        self.layoutIfNeeded()
        super.setTitle(title, forState: state)
        UIView.setAnimationsEnabled(true)
    }

}
Community
  • 1
  • 1
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • I tried this approach (subclassing, overriding setTitle:forState: and disabling-enabling UIView.setAnimationsEnabled). Not working for me in iOS 9 and 10 beta. It works if I only disable the animations, but then they're lost for every UIView... – cdf1982 Aug 09 '16 at 09:42
3

Try this, this works in newer versions of IOS:

class CustomButtonWithNoEffect : UIButton {
    override func setTitle(_ title: String?, for state: UIControlState) {
        UIView.performWithoutAnimation {
            super.setTitle(title, for: state)
            super.layoutIfNeeded()
        }
    }

}
Kárpáti András
  • 1,221
  • 1
  • 16
  • 35
0

I'm new to coding and Stackoverflow, so don't have enough reputation to comment directly to expand on https://stackoverflow.com/users/4673064/daniel-tseng excellent answer. So I have to write my own new answer, and it is this:

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

Works great, EXCEPT:

If all my calls later on in the code to "setTitleWithoutAnimation" do not specify a sender, then I get these weird messages related to CoreMedia or CoreData, e.g., "Failed to inherit CoreMedia permissions from 2526: (null)"

This is probably pretty basic to coding and iOS, but for me as a new coder, it sent me on a rabbit trail for a while, as in: Today Extension Failed to inherit CoreMedia permissions from, where people had interesting answers but that did NOT reach the root of my problem.

So I finally found that I had to go through and give my parameter-less functions parameters, i.e., I had to specify a sender. That sender could be UIButton, Any, or AnyObject. All of those worked, but ultimately there appears to be a conflict between adding a button extension with "self" and not specifically saying later on that a button is using it.

Again, probably basic, but new to me, so I figured it would be worth sharing.

0

Another trick

@IBOutlet private weak var button: UIButton! {
    didSet {
        button.setTitle(title, for: .normal)
    }
}

This works only if you know the value of the title without making any API calls. The button's title will be set before the view is loaded so you won't see the animation

TunaTheDog
  • 33
  • 6