Як зупинити небажану анімацію UIButton при зміні заголовка?


211

У iOS 7 мої назви UIButton анімують та виходять не в той час - пізно. Ця проблема не з’являється на iOS 6. Я просто використовую:

[self setTitle:text forState:UIControlStateNormal];

Я б хотів, щоб це сталося миттєво і без порожнього кадру. Це моргання особливо відволікає і відтягує увагу від інших анімацій.


Ми також переживаємо це. Не впевнений, це помилка iOS7 чи щось, що ми повинні виправити.
Похит

Спробуйте, [self.button setHighlirated: NO];
karthika

Дякую за ці ідеї. Я спробував встановити виділене: НІ, але не пощастило. Я в змозі зменшити моргання, помістивши setTitle всередину: [UIView animateWithDuration: 0.0f анімації: ^ {...}];
exsulto

1
Ви можете використовувати цей метод обходу в деяких випадках: self.button.titleLabel.text = text. Але це не змінює розмір кадру етикетки і не працює правильно з UIControlStates
zxcat

Це розумне рішення. Я пограю з цим і побачу, що станеться, на жаль, я використовую UIControlStates.
exsulto

Відповіді:


165

Це працює для користувацьких кнопок:

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

Для системних кнопок потрібно додати це перед повторним увімкненням анімації (дякую @Klaas):

[_button layoutIfNeeded];

12
На жаль, це, здається, не працює. Жоден з них виконує без Анімації
Sway

9
Гаразд, тому виправлення, яке спрацювало в кінці кінців, полягало в тому, щоб залишити початковий текст UIButton порожнім, щоб, коли я встановив його з кодом, він не запускав анімацію.
Sway

27
Це працює лише в тому випадку, якщо ви встановили тип кнопки на звичайний, відповідно до цієї відповіді stackoverflow.com/a/20718467/62 .
Лірон Ягдав

15
До iOS 7.1 мені довелося додати[_button layoutIfNeeded];
Klaas

6
@LironYahdav, якщо у вас тип кнопки встановлено на UIButtonTypeCustom, тоді ця відповідь не потрібна.
DonnaLea

262

Скористайтеся performWithoutAnimation:методом, а потім змушуйте макет відбуватися негайно, а не пізніше.

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

11
Це працює так само, як і прийнята відповідь, але здається приємнішим, оскільки він більш капсульований - неможливо забути додати [UIView setAnimationsEnabled: ТАК], або для того, щоб його видалити вниз по трасі.
siburb

19
Він працює для системних кнопок, якщо ви телефонуєте [button layoutIfNeeded];всередині блоку.
Олександр Блін

1
До речі, для кнопок системи, layoutIfNeed повинна викликатися після того, як текст змінений
Йон

Це найкраще рішення! Ура
сахадсо

Це для мене правильне. Він найбільше проголосував і на 6-му місці. Приємно ...
сольгар

79

Змініть тип кнопки на спеціальний конструктор інтерфейсу форми.

введіть тут опис зображення

Це працювало для мене.


6
Найкраще рішення! Дякую.
Томас Кальмон

3
Але це також відключає анімацію при натисканні кнопки. Я хочу відключити анімацію лише на кнопці показу.
Piotr Wasilewicz

Це працює, якщо вам не хвилюється анімація, коли натискаєте кнопку.
Хоакін Перейра

У мене було кілька кнопок, встановлених так, і, очевидно, це найелегантніша відповідь для мого випадку. Приємно, дякую!
Золтан

79

У Swift ви можете використовувати:

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

1
Це був, безумовно, найпростіший метод. І дякую, що включили швидку відповідь btw
simplexity

1
Найкраща відповідь для Свіфта!
Нубаслон

Була роздратована помилка, коли зміна заголовка UIButton під час екрану спричинила б дивні таймінги анімації за допомогою interactivePopGestureRecognizer, і це вирішило її. Я все ще думаю, що це помилка з ОС
SparkyRobinson

Дивно, що потрібно викликати .layoutIfNeeded (), але я тестував його обома способами у Swift 5, і він безперечно анімує без нього.
wildcat12

2
Не зовсім. Якщо ви не зателефонували, layoutIfNeeded()то ця кнопка позначена як потрібна для перемальовування, але це не відбудеться до наступного пропуску макета, який буде поза межамиperformWithoutAnimation
Paulw11

60

Будь ласка, запиши :

коли " buttonType " _button - "UIButtonTypeSystem" , нижче код недійсний :

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

коли « buttonType » з _button є «UIButtonTypeCustom» , наведений вище код є дійсним .


Не можу повірити, скільки часу я витратив, перш ніж з'ясувати, вам просто потрібно змінити тип кнопки ... так ...
Сенді Чапман

Працює без будь-якого коду. Змініть лише тип кнопок, і це спрацює.
Alex Motor

52

Починаючи з iOS 7.1, єдине рішення, яке працювало для мене, - ініціалізація кнопки з типом UIButtonTypeCustom.


Це найбільш розумний підхід для тих, хто не потребує UIButtonTypeSystem.
DonnaLea

Це закінчилося для мене найкращим чином, я просто створив КОРИСТУЮ кнопку і зробив її виглядом і виділенням, як кнопка системи. Навряд чи видно різницю, але у вас немає такої затримки.
Травіс М.

18

тому я знаходжу відпрацьоване рішення:

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

спочатку ми змінюємо заголовок на кнопку, потім кнопку зміни розміру для цього заголовка


1
Я використовую той самий спосіб вирішення. Прийнята відповідь не працює для мене.
deej

Це призводить до того, що заголовок спалахує двічі, принаймні, з iOS 8.
Jordan H

1
Це працює для мене як в 7.1, так і в 8.1 без миготіння. Простий і ефективний.
Тодд

Відмінно працює в iOS 11, хоча мені довелося знову використовувати той самий рядок для другого рядка (використання заголовка мітки кнопки спричинило миготіння).
SilverWolf - Відновіть Моніку

13

Встановіть тип кнопки на UIButtonTypeCustom, і вона перестане блимати


Як у всіх цих шляхових "рішень" є стільки результатів, коли ця проста відповідь повинна вирішити це питання 99% часу ...
Роб


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 має бути схожим)


Не збираюся використовувати це зараз, але дуже зручно мати навколо!
Френсіс Рейнольдс

9

Встановіть тип UIButton як власний. Це повинно видалити анімацію зникнення та вимкнення.


1
Це повинно мати більше оновлень! Відмінно працює і замість цих інших способів усунення анімації в першопричині.
Jesper Schläger

7

Зазвичай просто встановлення типу кнопки на Custom працює для мене, але з інших причин мені потрібно було підкласифікувати UIButton і повернути тип кнопки назад за замовчуванням (System), щоб миготіння знову з’явилося.

Якщо встановити UIView.setAnimationsEnabled(false)перед тим, як змінити назву, а потім знову встановити істину, це не уникне моргання для мене, незалежно від того, закликав я 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, не потрібно змінювати її на Custom Type, щоб цей підхід працював.

Я сподіваюся, що це допомагає комусь іншому, я так довго боровся з набридливими миготливими кнопками, що сподіваюся уникнути цього перед іншими;)


Не забувайте layoutIfNeeded():]
Tai Le

6

Ви можете просто створити спеціальну кнопку, і вона перестане анімувати під час зміни заголовка.

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

ви також можете зробити це у вікні "Розгортка": встановіть кнопку в дошці розкадрувань -> виберіть інспектор атрибутів (четверта з лівої сторони) -> у спадному меню "Тип" виберіть "Користувальницький" замість "Система", яку, ймовірно, вибрали .

Удачі!


3

Ви можете видалити анімації зі шару мітки заголовка:

    [[[theButton titleLabel] layer] removeAllAnimations];

Я пройшов усі відповіді. Цей найкращий.
Рудольф Адамкович

2
Він все ще блимає, але краще.
Люсьєн

ЦЕ ПОВИНЕН БУТИ ВІДПОВІДЬ.
mxcl

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

UIButton з systemтипом увімкнено неявну анімацію setTitle(_:for:). Ви можете виправити це двома різними способами:

  1. Встановіть тип кнопки customз коду чи з Інтерфейсу:
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.
sCha

не думаю, що ви знайшли рішення для 7.1?
Джордж Грін

@GeorgeGreen не зміг знайти жодних робочих рішень для UIButtonTypeSystem . Довелося користуватися UIButtonTypeCustom .
sCha

Починаючи з 7.1, вам потрібно буде застосувати зміни заголовка до всіх станів, встановивши його лише для нормального стану, більше не застосовується. [_button setTitle:@"title" forState:UIControlStateDisabled]
Сем

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. Отже, щоб все-таки використовувати майданчики розкадрувань та мати такі компоненти, як динамічно локалізуватись, я обов'язково встановіть ідентифікатор відновлення кожної кнопки (в інспекторі ідентичності) таким самим, як заголовок, і використовуйте його як ключ замість заголовка;

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. Відповідає API API для Apple UIButton.
Річард Топчій
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.