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

Posted

技术标签:

【中文标题】如何在标题更改时停止不需要的 UIButton 动画?【英文标题】:How to stop unwanted UIButton animation on title change? 【发布时间】:2013-09-27 14:18:27 【问题描述】:

ios 7 中,我的 UIButton 标题在错误的时间进出动画 - 延迟。这个问题在 iOS 6 上没有出现。我只是在使用:

[self setTitle:text forState:UIControlStateNormal];

我希望这种情况立即发生并且没有空白框。这种眨眼尤其会分散注意力,并将注意力从其他动画上移开。

【问题讨论】:

我们也遇到了这种情况。不确定这是 iOS7 的错误还是我们应该修复的问题。 试试,[self.button setHighlighted:NO]; 感谢这些想法。我试过 setHighlighted:NO,但没有运气。我可以通过将 setTitle 放在里面来减少眨眼: [UIView animateWithDuration:0.0f animations:^ ... ]; 您可以在某些情况下使用此解决方法:self.button.titleLabel.text = text。但这不会调整标签框架的大小,也不能正确使用 UIControlStates 这是一个聪明的解决方法。我会玩这个,看看会发生什么,不幸的是我正在使用 UIControlStates。 【参考方案1】:

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

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

【讨论】:

这与公认的答案一样有效,但似乎更好,因为它更加封装 - 不可能忘记添加 [UIView setAnimationsEnabled:YES],或者将其从轨道上删除. 如果您在块内调用[button layoutIfNeeded];,它适用于系统按钮。 顺便说一句,对于系统按钮,layoutIfNeed 应该在 文本更改后调用 这是最好的解决方案!干杯 这对我来说是正确的。它的投票最多,排在第 6 位。不错...【参考方案2】:

这适用于自定义按钮:

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

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

[_button layoutIfNeeded];

【讨论】:

不幸的是,这似乎不起作用。 performWithoutAnimation 也没有 好的,所以最终的解决方法是将原始 UIButton 文本留空,这样当我用代码设置它时它不会触发动画。 这仅在您将按钮的类型设置为自定义时才有效,根据此答案***.com/a/20718467/62。 从 iOS 7.1 开始,我必须添加 [_button layoutIfNeeded]; @LironYahdav 如果您将按钮类型设置为 UIButtonTypeCustom,则不需要此答案。【参考方案3】:

在 Swift 中你可以使用:

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

【讨论】:

这是迄今为止最简单的方法。并感谢您提供一个快速的回答顺便说一句 Swift 的最佳答案! 有一个烦人的错误,即在屏幕外更改 UIButton 标题会导致使用 interactivePopGestureRecognizer 产生奇怪的动画计时,这解决了它。我仍然认为这是操作系统的错误 奇怪的是 .layoutIfNeeded() 必须被调用,但我在 Swift 5 中对它进行了两种测试,没有它它肯定仍然可以动画。 并非如此。如果您不调用layoutIfNeeded(),则该按钮将被标记为需要重绘,但这要等到下一个布局通过之后才会发生,这将在performWithoutAnimation之外。【参考方案4】:

将按钮类型更改为自定义表单界面生成器。

这对我有用。

【讨论】:

最佳解决方案!谢谢。 但这也会禁用点击按钮上的动画。我只想在显示按钮时禁用动画。 如果您不关心点击按钮时的动画效果,则此方法有效。 我已经设置了几个这样的按钮,显然这对我的案例来说是最优雅的答案。很好,谢谢!【参考方案5】:

请注意:

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

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

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

【讨论】:

不敢相信我花了多少时间才弄清楚你只需要更改按钮类型......呃...... 无需任何代码即可工作。只需更改按钮类型即可。【参考方案6】:

从 iOS 7.1 开始,唯一对我有用的解决方案是使用 UIButtonTypeCustom 类型初始化按钮。

【讨论】:

这对于不需要 UIButtonTypeSystem 的人来说是最明智的方法。 这对我来说效果最好,我刚刚创建了一个 CUSTOM 按钮,让它看起来像系统按钮一样突出显示。几乎看不出区别,但你没有那种延迟。【参考方案7】:

斯威夫特 5

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

【讨论】:

不知道为什么会这样,但它确实有效,而且它是最干净的解决方案。 UIKit 很奇怪。 不,它不是一个干净的解决方案,但它很脏,因为这可能会随任何 iOS 改变 @NathanHosselton 查看 dubenko 在 2014 年 4 月 22 日的回答。 “首先我们更改按钮的标题,然后调整此标题的按钮大小”【参考方案8】:

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

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

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

【讨论】:

我使用相同的解决方法。接受的答案对我不起作用。 这会导致标题闪烁两次,至少在 iOS 8 中是这样。 这在 7.1 和 8.1 中都适用于我,无需闪烁。简单有效。 在 iOS 11 中完美运行,尽管我不得不在第二行再次使用相同的字符串(使用按钮标签的标题导致它闪烁)。【参考方案9】:

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

【讨论】:

当这个简单的答案必须在 99% 的时间里解决这个问题时,所有那些变通的“解决方案”怎么会有这么多的赞成票......【参考方案10】:

我为此做了一个 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应该差不多)

【讨论】:

现在不打算用了,但是用起来很方便!【参考方案11】:

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

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

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

【讨论】:

【参考方案12】:

将 UIButton 类型设置为自定义。这应该会移除淡入淡出动画。

【讨论】:

这应该有更多的赞成票!完美运行并从根本原因禁用动画,而不是这些其他解决方法。【参考方案13】:

通常简单地将按钮类型设置为自定义对我来说是可行的,但由于其他原因,我需要子类化 UIButton 并将按钮类型设置回默认值(系统),所以闪烁再次出现。

在更改标题之前设置UIView.setAnimationsEnabled(false),然后再设置为true,无论我是否调用self.layoutIfNeeded(),都无法避免闪烁。

这个,并且只有这个按照以下确切顺序,在 iOS 9 和 10 测试版中对我有用:

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() :]【参考方案14】:

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

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

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

祝你好运!

【讨论】:

【参考方案15】:

Swift 4 版 Xhacker 刘回答

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

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    
 

【讨论】:

【参考方案16】:

您可以从标题标签的图层中删除动画:

    [[[theButton titleLabel] layer] removeAllAnimations];

【讨论】:

我浏览了所有答案。这个是最好的。 它仍然在闪烁,但已经更好了。 这应该是答案。【参考方案17】:

您实际上可以在动画块之外设置标题,只要确保在 performWithoutAnimation 中调用 layoutIfNeeded()

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()

【讨论】:

【参考方案18】:

我发现此解决方法也适用于 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 自 7.1 起,您需要将标题更改应用到所有状态,将其设置为仅适用于正常状态不再适用。 [_button setTitle:@"title" forState:UIControlStateDisabled]【参考方案19】:

结合以上出色的答案,可以为 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];

【讨论】:

【参考方案20】:

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


不理想,但有效..

【讨论】:

【参考方案21】:

Xhacker Liu 扩展转换为 Swift 3:

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

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    

【讨论】:

【参考方案22】:

一个方便的 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 的 UIButton API 一致。【参考方案23】:

我得到了它的答案组合:

[[[button titleLabel] layer] removeAllAnimations];

    [UIView performWithoutAnimation:^

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

    ];

【讨论】:

【参考方案24】:

也许生成 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;];

【讨论】:

以上是关于如何在标题更改时停止不需要的 UIButton 动画?的主要内容,如果未能解决你的问题,请参考以下文章

UIButton 突然停止工作

滚动时更改 UIButton 色调颜色

根据状态更改 UIButton 中 ImageView 的 tint 颜色

触摸按钮时如何更改 UIButton 图像

点击时如何更改 UIButton 的标题颜色? [复制]

当用户在 UIButton 上滑动时,UIScrollView 停止工作