更新标题时如何防止UIButton闪烁


85

当我在UIButton上调用setTitle时,按钮在iOS 7中闪烁。我尝试设置myButton.highlighted = NO,但这并没有阻止按钮闪烁。

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

myButton.highlighted = NO;

这是我设置计时器以更新标题的方式:

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

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

这是实际更新标题的方法:

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

它不应该闪烁。您是否要在后台线程上执行此操作?
BergQuester

是的,它是在计时器中设置的,用于每秒更新按钮标题(我认为这是创建自己的线程)
FierceMonkey 2013年

如果设置了计时器,则计时器仅在单独的线程上运行。我们能否看到标题更新的方法以及如何设置计时器?
BergQuester

我加入了请求的代码的主要问题
FierceMonkey

Answers:


205

将按钮类型设置为UIButtonTypeCustom,它将停止闪烁


16
这确实应该是首选的答案。最简单的解决方案。而且它正在工作。
约翰·卡尔森

4
同意 我尝试了许多其他解决方案,而这些都是靠它自己完成的。
BBQ Steve

2
这应该是公认的答案。到目前为止最简单的解决方案。
马查多

1
奇迹般有效!谢谢

2
我认为这是一个非常好的解决方案,无需为此编写任何代码。
Chauyan

55

一个比[UIView setAnimationsEnabled:NO]可能会影响其他动画更好的方法是仅禁用特定的标题动画。

目标C:

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

迅速:

UIView.performWithoutAnimation { 
    myButton.setTitle(text, for: .normal)
    myButton.layoutIfNeeded()
}

刚刚在最新的iOS上试用了Swift解决方案-效果很好。
罗恩·拉比诺维奇

1
天救星。干杯!
pkc456

刚刚在Swift 3中尝试过,它无需使用layoutIfNeeded()即可工作
user1898712

3
毫无疑问,这应该是公认的答案!
Julius

1
这是执行此操作的最佳方法。好答案!
登场

29

*请注意*

什么时候 ”_button的 buttonType ”为“ UIButtonTypeSystem”时,以下代码无效

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

_button的buttonType ”为“ UIButtonTypeCustom”时,以上代码为有效


19

请参阅“如何在标题更改时停止不需要的UIButton动画”中的响应

[UIView setAnimationsEnabled:NO];
[elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

7
@FierceMonkey尝试将呼叫添加到layoutIfNeeded[elapsed layoutIfNeeded];。就我而言,这消除了闪烁。
克拉斯

1
layoutIfNeeded为我做了。
高岭土大火

这似乎是一个相当肮脏的解决方法,但是layoutIfNeeded似乎
可行。

7

您只需为UIButton制作另一个函数即可,以方便将来使用。

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

这就对了!

只需像以前一样设置标题,然后替换setTitlesetTitleWithoutAnimation


6

默认的“ setTitle”行为绝对是可恶的!

我的解决方案是:

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

另外,在情节提要中,在按钮的属性下,我取消选中:

  • 高亮反转
  • 突出显示的调整图像

并检查:

  • 禁用调整图像

测试并也在iOS 8上工作。

更新-Swift

我建议您创建自定义按钮并覆盖setTitle方法。

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

}

我尝试了这种方法(子类化,覆盖setTitle:forState:和禁用启用UIView.setAnimationsEnabled)。在iOS 9和10 Beta中不适用于我。如果我仅禁用动画,它会起作用,但是每个UIView都会丢失它们……
cdf1982

2

试试看,这在新版本的IOS中有效:

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

}

0

我是编码和Stackoverflow的新手,所以没有足够的声誉直接发表评论以扩展到https://stackoverflow.com/users/4673064/daniel-tseng出色的答案。所以我必须写自己的新答案,就是这样:

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

效果很好,除了:

如果我稍后在代码中对“ setTitleWithoutAnimation”的所有调用均未指定发送者,那么我会收到与CoreMedia或CoreData相关的这些奇怪消息,例如,“未能从2526继承CoreMedia权限:(空)”

这可能是编码和iOS的基本知识,但是对于我来说,这是一种新的编码器,它使我经历了一段时间的兔子跟踪,例如:今日扩展程序无法从继承CoreMedia权限,那里的人们有有趣的答案,但没有达到我问题的根源。

因此,我终于发现我必须仔细检查并给无参数的函数提供参数,即必须指定发送者。该发送者可以是UIButton,Any或AnyObject。所有这些都有效,但是最终在添加带有“ self”的按钮扩展名与稍后不专门说按钮正在使用它之间似乎存在冲突。

再说一次,可能是基本的,但对我来说是新手,所以我认为值得分享。


0

另一招

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

仅当您知道标题的值而不进行任何API调用时,此方法才有效。该按钮的标题将在加载视图之前设置,因此您不会看到动画

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.