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

137

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

[self setTitle:text forState:UIControlStateNormal];

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

  • 0
    Мы тоже переживаем это. Не уверен, что это ошибка iOS7 или что-то, что мы должны исправить.
  • 0
    Попробуйте, [self.button setHighlighted: NO];
Показать ещё 5 комментариев
Теги:
uibutton
uikit
ios7

20 ответов

124
Лучший ответ

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

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

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

[_button layoutIfNeeded];
  • 0
    Это исправление устраняет мигание полностью - приятно.
  • 12
    К сожалению, это не похоже на работу. Никто не выполняет без анимации
Показать ещё 17 комментариев
186

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

[UIView performWithoutAnimation:^{
  [self.myButton setTitle:text forState:UIControlStateNormal];
  [self.myButton layoutIfNeeded];
}];
  • 10
    Это работает так же, как и принятый ответ, но кажется более приятным, потому что он более инкапсулирован - невозможно забыть добавить [UIView setAnimationsEnabled: YES] или удалить его в дальнейшем.
  • 3
    это не работает для меня (xcode 6, ios8 simulator)
Показать ещё 5 комментариев
54

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

когда "buttonType" кнопки _ "UIButtonTypeSystem" , ниже кода недействителен:

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

когда "buttonType" of_button "UIButtonTypeCustom" , код выше действителен.

  • 3
    Очень важно, что это работает только на Custom. Спасибо :)
  • 0
    Не могу поверить, сколько времени я потратил, прежде чем понять, тебе просто нужно изменить тип кнопки ... тьфу ...
Показать ещё 1 комментарий
39

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

  • 0
    Это самый разумный подход для тех, кто не требует UIButtonTypeSystem.
  • 0
    Это оказалось лучше всего для меня, я просто создал кнопку CUSTOM и сделал ее похожей на системную кнопку. Вряд ли вижу разницу, но у вас нет этой задержки.
36

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

Изображение 1838

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

  • 0
    Это работало в iOS 8.0 xcode 6.4
  • 5
    Лучшее решение! Спасибо.
Показать ещё 3 комментария
30

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

UIView.performWithoutAnimation {
    self.someButtonButton.setTitle(newTitle, forState: .normal)
    self.someButtonButton.layoutIfNeeded()
}
  • 0
    Это был безусловно самый простой метод. И спасибо, что включили быстрый ответ, кстати
  • 0
    Лучший ответ для Swift!
Показать ещё 1 комментарий
16

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

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

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

  • 5
    Это некрасиво, но это работает.
  • 1
    Я использую тот же обходной путь. Принятый ответ не работает для меня.
Показать ещё 3 комментария
12

Ive сделал расширение 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 должен быть похож)

  • 0
    Не собираюсь использовать его сейчас, но очень удобно иметь рядом!
7

Задайте тип кнопки UIButtonTypeCustom, и она перестанет мигать

5

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

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

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

Удачи!

3

Вы можете удалить анимации из слоя надписи:

    [[[theButton titleLabel] layer] removeAllAnimations];
  • 0
    Я прошел через все ответы. Этот лучший.
  • 1
    не работает для меня
Показать ещё 2 комментария
1

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

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

        setTitle(title, for: .normal)

        layoutIfNeeded()
        UIView.setAnimationsEnabled(true)
    }
}
1

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

Настройка 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()
    })
}

В интерфейсе Builder вы можете оставить тип кнопки в Системе, не нужно менять ее на пользовательский тип, чтобы этот подход работал.

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

  • 0
    Не забывайте layoutIfNeeded() :]
1

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

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

}

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

1

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

  • 0
    Только что подтвердил, что этот обходной путь больше не работает на iOS 7.1.
  • 0
    не кажется, что вы нашли решение для 7.1?
Показать ещё 2 комментария
0

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

  • 0
    Это должно иметь больше голосов! Работает отлично и отключает анимацию по первопричине вместо этих других обходных путей.
0

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

[[[button titleLabel] layer] removeAllAnimations];

    [UIView performWithoutAnimation:^{

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

    }];
0

Возможно, создание 2 анимаций и 2 кнопок - лучшее решение, чтобы избежать проблемы, возникающей при анимации и изменении текста кнопки?

Я создал вторую uibutton и сгенерировал 2 анимации, это решение работает без hickup.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню