如何在标题更改时停止不需要的UIButton动画?


211

在iOS 7中,我的UIButton标题会在错误的时间(迟到)动画设置。在iOS 6上不会出现此问题。我只是在使用:

[self setTitle:text forState:UIControlStateNormal];

我希望这种情况立即发生,并且没有空白框。这种眨眼特别令人分心,并吸引了其他动画的注意力。


我们也正在经历这种情况。不知道这是iOS7错误还是我们应该修复的问题。
2013年

试试,[self.button setHighlighted:NO];
karthika

感谢这些想法。我尝试了setHighlighted:NO,但是那里没有运气。我可以通过将setTitle放入其中来减少眨眼:[UIView animateWithDuration:0.0f animations:^ {...}];
exsulto 2013年

1
在某些情况下,您可以使用此解决方法:self.button.titleLabel.text = text。但这不会调整标签框架的大小,并且无法正确使用UIControlStates
zxcat13年

这是一个聪明的解决方法。我会玩这个,看看会发生什么,不幸的是我正在使用UIControlStates。
13年

Answers:


165

这适用于自定义按钮:

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

对于系统按钮,您需要在重新启用动画之前添加此按钮(感谢@Klaas):

[_button layoutIfNeeded];

12
不幸的是,这似乎不起作用。performWithoutAnimation都没有
摇摆

9
好的,最后解决的办法是将原始的UIButton文本保留为空白,以便在我使用代码进行设置时不会触发动画。
2013年

27
按照此答案stackoverflow.com/a/20718467/62,只有将按钮的类型设置为custom时,此方法才有效。
Liron Yahdav 2014年

15
从iOS 7.1开始,我不得不添加[_button layoutIfNeeded];
Klaas

6
@LironYahdav如果您将按钮类型设置为UIButtonTypeCustom,则不需要此答案。
DonnaLea 2014年

262

使用该performWithoutAnimation:方法,然后强制立即进行布局,而不是稍后进行。

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

11
这和已接受的答案一样有效,但是看起来更好,因为它封装的更好-不能忘记添加[UIView setAnimationsEnabled:YES]或将其移除。
siburb 2014年

19
如果您[button layoutIfNeeded];在块内调用,它适用于系统按钮。
亚历山德拉·布林

1
顺便说一句,对于系统按钮,更改文本应调用layoutIfNeed
2015年

这是最好的解决方案!干杯
sachadso '16

这对我来说是正确的。投票最多,排名第六。尼斯...
索尔加

79

将按钮类型更改为定制表单界面构建器。

在此处输入图片说明

这对我有用。


6
最好的解决方案!谢谢。
托马斯·卡尔蒙

3
但这也会禁用单击按钮上的动画。我只想在显示按钮上禁用动画。
Piotr Wasilewicz

如果您在点击按钮时不关心动画,则可以使用此方法。
华金·佩雷拉

我有几个这样的按钮设置,显然这是我的案例中最优雅的答案。很好,谢谢!
佐尔坦

79

在Swift中,您可以使用:

UIView.performWithoutAnimation {
    self.someButtonButton.setTitle(newTitle, forState: .normal)
    self.someButtonButton.layoutIfNeeded()
}

1
到目前为止,这是最简单的方法。谢谢您的迅速回答
单纯性,

1
Swift的最佳答案!
Nubaslon

有一个烦人的错误,即在屏幕外更改UIButton标题会导致使用InteractivePopGestureRecognizer产生奇怪的动画计时,从而解决了这一问题。我仍然认为这是操作系统的错误
SparkyRobinson

必须调用.layoutIfNeeded()很奇怪,但是我在Swift 5中都对它进行了测试,并且肯定没有它也会设置动画。
wildcat12

2
并不是的。如果您不拨打电话,layoutIfNeeded()则该按钮会被标记为需要重绘,但直到下一次布局通过时才会发生,这将在performWithoutAnimation
Paulw11

60

请注意 :

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

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

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


不敢相信我花了多少时间才弄清楚你只需要更改按钮的类型…………
Sandy Chapman

无需任何代码即可工作。仅更改按钮类型即可使用。
Alex Motor

52

从iOS 7.1开始,唯一适用于我的解决方案是使用type初始化按钮UIButtonTypeCustom


对于不需要UIButtonTypeSystem的任何人来说,这都是最明智的方法。
DonnaLea 2014年

最后,这对我来说效果最好,我刚刚创建了一个CUSTOM按钮,并使它看起来像系统按钮一样突出显示。几乎看不到差异,但您没有延迟。
特拉维斯·

18

所以我找到了可行的解决方案:

_logoutButton.titleLabel.text = NSLocalizedString(@"Logout",);
[_logoutButton setTitle:_logoutButton.titleLabel.text forState:UIControlStateNormal];

首先,我们更改按钮的标题,然后调整此标题的按钮大小


1
我使用相同的解决方法。接受的答案对我不起作用。
deej 2014年

这使得标题闪烁两次,至少与iOS 8.
约旦ħ

1
这对我来说在7.1和8.1中都适用,而不会闪烁。简单有效。
托德

尽管我不得不在第二行中再次使用相同的字符串(使用按钮标签的标题导致其闪烁),但它在iOS 11中可以完美运行。
SilverWolf-恢复莫妮卡

13

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


当这个简单的答案必须在99%的时间解决此问题时,所有这些变通办法“解决方案”怎么会有这么多的票数……
Rob

12

迅捷5

myButton.titleLabel?.text = "title"
myButton.setTitle("title", for: .normal)

不知道为什么会这样,但确实如此,这是最干净的解决方案。UIKit很奇怪。
内森·霍瑟尔顿

11

我做了一个Swift扩展来做到这一点:

extension UIButton {
    func setTitleWithoutAnimation(title: String?) {
        UIView.setAnimationsEnabled(false)

        setTitle(title, forState: .Normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}

适用于我在iOS 8和9上运行的UIButtonTypeSystem

(用于Swift 2,Swift 3和Objective-C的代码应该相似)


现在不打算使用它,但是非常方便!
弗朗西斯·雷诺兹


7

通常,通常只需将按钮类型设置为Custom即可,但是由于其他原因,我需要继承UIButton并将其按钮类型恢复为默认值(系统),因此闪烁再次出现。

UIView.setAnimationsEnabled(false)更改标题之前先进行设置,然后再更改为true,无论我是否打电话,都无法避免闪烁self.layoutIfNeeded()

这,并且仅按照以下确切顺序,才对我适用于iOS 9和10 beta:

1)为UIButton创建一个子类(也不要忘记在Storyboard中为按钮设置自定义类)。

2)覆盖setTitle:forState:如下:

override func setTitle(title: String?, forState state: UIControlState) {

    UIView.performWithoutAnimation({

        super.setTitle(title, forState: state)

        self.layoutIfNeeded()
    })
}

在Interface Builder中,您可以将按钮类型保留为System,而无需将其更改为Custom Type即可使用此方法。

我希望这对其他人有帮助,我已经通过烦人的闪烁按钮苦苦挣扎了很长时间,希望可以避免对其他人使用它;)


别忘了layoutIfNeeded():]
Tai Le

6

您可以简单地创建“自定义”按钮,并且在更改标题时它将停止动画。

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [btn setTitle:@"the title" forState:UIControlStateNormal];

您也可以在Storyboard复选框中执行此操作:在Storyboard中选择按钮->选择“属性”检查器(从左数第四)->在“类型”下拉菜单中,选择“自定义”而不是可能选择的“系统” 。

祝好运!



3

Swift 4版本的Xhacker Liu回答

import Foundation
import UIKit
extension UIButton {
    func setTitleWithOutAnimation(title: String?) {
        UIView.setAnimationsEnabled(false)

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
} 

1

system类型的UIButton在上具有隐式动画setTitle(_:for:)。您可以通过两种不同的方式修复它:

  1. custom从代码或Interface Builder 将按钮类型设置为:
let button = UIButton(type: .custom)

在此处输入图片说明

  1. 禁用代码中的动画:
UIView.performWithoutAnimation {
    button.setTitle(title, for: .normal)
    button.layoutIfNeeded()
}

0

我发现该解决方法也可以与UIButtonTypeSystem一起使用,但是仅在由于某种原因启用了按钮的情况下才可以使用。

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

因此,如果需要在设置标题时禁用该按钮,则必须添加这些内容。

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

(iOS 7,Xcode 5)


刚刚确认,此解决方法不再适用于iOS 7.1。
沙卡

没想到您找到了7.1的解决方案?
乔治·格林

@GeorgeGreen找不到UIButtonTypeSystem的任何有效解决方案。我不得不使用UIButtonTypeCustom
2014年

从7.1开始,您需要将标题更改应用于所有状态,仅将其设置为普通状态就不再适用。[_button setTitle:@"title" forState:UIControlStateDisabled]
2014年

0

结合以上很好的答案,将导致以下UIButtonTypeSystem解决方法:

if (_button.enabled)
{
    [UIView setAnimationsEnabled:NO];
    [_button setTitle:@"title" forState:UIControlStateNormal];
    [UIView setAnimationsEnabled:YES];
}
else // disabled
{
    [UIView setAnimationsEnabled:NO];
    _button.enabled = YES;
    [_button setTitle:@"title" forState:UIControlStateNormal];
    _button.enabled = NO;
    [UIView setAnimationsEnabled:YES];
}

0

在UITabBarController的视图控制器中更改按钮标题时遇到了丑陋的动画问题。最初在情节提要中设置的标题会出现一小段时间,然后逐渐淡化为新值。

我想遍历所有子视图,并使用按钮标题作为键来通过NSLocalizedString获取其本地化值,例如;

for(UIView *v in view.subviews) {

    if ([v isKindOfClass:[UIButton class]]) {
        UIButton *btn = (UIButton*)v;
        NSString *newTitle = NSLocalizedString(btn.titleLabel.text, nil);
        [btn setTitle:newTitle];
    }

}

我发现触发动画的实际上是对btn.titleLabel.text的调用。因此,为了仍然使用情节提要板并像这样动态地对组件进行本地化,我确保将每个按钮的“还原ID”(在Identity Inspector中)设置为与标题相同,并将其用作键而不是标题。

for(UIView *v in view.subviews) {

    if ([v isKindOfClass:[UIButton class]]) {
        UIButton *btn = (UIButton*)v;
        NSString *newTitle = NSLocalizedString(btn.restorationIdentifier, nil);
        [btn setTitle:newTitle];
    }

}

不理想,但是可以。


0

您实际上可以在动画块外部设置标题,只需确保layoutIfNeeded()在performWithoutAnimation内部调用即可:

button1.setTitle("abc", forState: .Normal)
button2.setTitle("abc", forState: .Normal)
button3.setTitle("abc", forState: .Normal)
UIView.performWithoutAnimation {
    self.button1.layoutIfNeeded()
    self.button2.layoutIfNeeded()
    self.button3.layoutIfNeeded()
}

如果您有一堆按钮,请考虑仅layoutIfNeeded()在超级视图上调用:

button1.setTitle("abc", forState: .Normal)
button2.setTitle("abc", forState: .Normal)
button3.setTitle("abc", forState: .Normal)
UIView.performWithoutAnimation {
    self.view.layoutIfNeeded()
}

0

Xhacker Liu扩展转换为Swift 3:

extension UIButton {
    func setTitleWithoutAnimation(title: String?) {
        UIView.setAnimationsEnabled(false)

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}

-1

也许生成2个动画和2个按钮是更好的解决方案,以避免动画和更改按钮文本时出现的问题?

我创建了第二个uibutton并生成了2个动画,该解决方案可以正常使用。

    _button2.hidden = TRUE;
    _button1.hidden = FALSE;

    CGPoint startLocation = CGPointMake(_button1.center.x, button1.center.y - 70);
    CGPoint stopLocation  = CGPointMake(_button2.center.x, button2.center.y- 70);


    [UIView animateWithDuration:0.3 animations:^{ _button2.center = stopLocation;} completion:^(BOOL finished){_button2.center = stopLocation;}];
    [UIView animateWithDuration:0.3 animations:^{ _button1.center = startLocation;} completion:^(BOOL finished){_button1.center = startLocation;}];

-1

我将其与答案结合使用:

[[[button titleLabel] layer] removeAllAnimations];

    [UIView performWithoutAnimation:^{

        [button setTitle:@"Title" forState:UIControlStateNormal];

    }];

-1

Swift中动画按钮标题更改的便捷扩展,可与默认实现完美配合:

import UIKit

extension UIButton {
  /// By default iOS animated the title change, which is not desirable in reusable views
  func setTitle(_ title: String?, for controlState: UIControlState, animated: Bool = true) {
    if animated {
      setTitle(title, for: controlState)
    } else {
      UIView.setAnimationsEnabled(false)
      setTitle(title, for: controlState)
      layoutIfNeeded()
      UIView.setAnimationsEnabled(true)
    }
  }
}

@Fogmeister 1.我的答案有所不同2.最新的Swift语法3.与Apple的API一致UIButton
理查德·托普奇
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.