【问题标题】:How to stop unwanted UIButton animation on title change?如何在标题更改时停止不需要的 UIButton 动画?
【发布时间】: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。

标签: objective-c swift ios7 uibutton uikit


【解决方案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 文本留空,这样当我用代码设置它时它不会触发动画。
  • 这仅在您将按钮的类型设置为自定义时才有效,根据此答案stackoverflow.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:) 上具有隐式动画。您可以通过两种不同的方式修复它:

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

  1. 从代码中禁用动画:
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;}];
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-02-17
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多