Как остановить нежелательную анимацию UIButton при изменении заголовка?

в iOS 7 мои заголовки UIButton анимируются и выходят в неправильное время-поздно. Эта проблема не отображается в iOS 6. Я просто использую:

[self setTitle:text forState:UIControlStateNormal];

Я бы предпочел, чтобы это произошло мгновенно и без пустой рамки. Это мигание особенно отвлекает и отвлекает внимание от других анимаций.

21 ответов


это работает для пользовательских кнопки:

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

для системных кнопок вам нужно добавить это перед повторным включением анимации (спасибо @Klaas):

[_button layoutIfNeeded];

использовать performWithoutAnimation: метод, а затем заставить макет произойти немедленно, а не позже.

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

обратите внимание :

, когда "buttonType" из-_button составляет "UIButtonTypeSystem", код недействительным

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

, когда "buttonType" из-_button составляет "UIButtonTypeCustom" выше код действительный.


изменить тип кнопки на пользовательский интерфейс формы builder.

enter image description here

Это работает для меня.


в Swift вы можете использовать:

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

начиная с iOS 7.1 единственным решением, которое сработало для меня, была инициализация кнопки с типом UIButtonTypeCustom.


поэтому я нахожу отработанное решение:

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

сначала мы меняем заголовок для кнопки, а затем изменяем размер кнопки для этого заголовка


Я сделал быстрое расширение, чтобы сделать это:

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 должен быть похожим)


Установите тип кнопки в UIButtonTypeCustom, и он перестанет мигать


вы можете просто создать пользовательскую кнопку, и она перестанет анимироваться при изменении заголовка.

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

вы также можете сделать это в поле раскадровки : выберите кнопку в раскадровке - > выберите инспектор атрибутов (четвертый слева) -> в раскрывающемся меню " тип "выберите" пользовательский "вместо " система", которая, вероятно, была выбрана.

удачи!


вы можете удалить анимацию из слоя метки заголовка:

    [[[theButton titleLabel] layer] removeAllAnimations];

установить тип UIButton как пользовательский. Это должно удалить fade In и out анимации.


обычно просто установка типа кнопки на пользовательские работы для меня, но по другим причинам мне нужно было подкласс UIButton и установить тип кнопки обратно в значение по умолчанию (система), поэтому мигание снова появилось.

задание UIView.setAnimationsEnabled(false) прежде чем изменить название, а затем снова true после этого не избежать мигания для меня, независимо от того, если я позвонил self.layoutIfNeeded() или нет.

это, и только это в следующем точном порядке, работало для меня с iOS 9 и 10 beta:

1) Создайте подкласс для UIButton (не забудьте также установить пользовательский класс для кнопки в раскадровке).

2) переопределить setTitle:forState: следующим образом:

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

    UIView.performWithoutAnimation({

        super.setTitle(title, forState: state)

        self.layoutIfNeeded()
    })
}

в Interface Builder вы можете оставить тип кнопки в System, не нужно менять его на пользовательский тип для этого подхода к работе.

надеюсь, это поможет кому-то еще, я так долго боролся с раздражающими мигающими кнопками, что надеюсь избежать этого другим ;)


я обнаружил, что этот метод работает с 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)


Я получил уродливую проблему анимации при изменении заголовков кнопок в контроллерах просмотра в 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.текст. Поэтому, чтобы по-прежнему использовать раскадровки и динамически локализовать компоненты, я обязательно устанавливаю идентификатор восстановления каждой кнопки (в 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];
    }

}

не идеально, но работает..


вы можете фактически установить заголовок вне блока анимации, просто не забудьте позвонить 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()
}

расширение Xhacker Liu преобразовано в Swift 3:

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

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}

объединение выше больших ответов приводит к следующему обходному пути для 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];
}

может быть, создание 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;}];

Я получил его для работы с комбинацией ответов:

[[[button titleLabel] layer] removeAllAnimations];

    [UIView performWithoutAnimation:^{

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

    }];

удобное расширение для изменения заголовка анимированной кнопки в 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)
    }
  }
}