Как предотвратить мигание UIButton при обновлении заголовка


85

Когда я вызываю setTitle в UIButton, кнопка мигает в iOS 7. Я попытался установить myButton.highlighted = NO, но это не остановило мигание кнопки.

[myButton setTitle:[[NSUserDefaults standardUserDefaults] stringForKey:@"elapsedLabelKey"] forState:UIControlStateNormal];

myButton.highlighted = NO;

Вот как я установил таймер, обновляющий заголовки:

- (void)actionTimer {
    if (myTimer == nil) {

        myTimer = [NSTimer scheduledTimerWithTimeInterval: 1.0
                        target: self
                        selector: @selector(showActivity)
                        userInfo: nil
                        repeats: YES];
    }
}

Вот метод, который фактически обновляет заголовки:

- (void)showActivity {

    NSString *sym = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencySymbol];

    if (pauseInterval == nil) {

        // Update clock
        seconds = [[NSDate date] timeIntervalSinceDate:startInterval] - breakTime;

        // Update total earned
        secRate = rate.value / 60 / 60;
        total = secRate * seconds;
        [totalLabel setTitle:[NSString stringWithFormat:@"%@%.4f",sym,total] forState:UIControlStateNormal];

        days = seconds / (60 * 60 * 24);
        seconds -= days * (60 * 60 * 24);
        int hours = seconds / (60 * 60);
        fhours = (float)seconds / (60.0 * 60.0);
        seconds -= hours * (60 * 60);
        int minutes = seconds / 60;
        seconds -= minutes * 60;

        // Update the timer clock
        [elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
    }
}

Он не должен мигать. Вы пытаетесь сделать это в фоновом потоке?
BergQuester

Да, он установлен в таймере для обновления заголовка кнопки каждую секунду (который, как мне кажется, создает отдельный поток)
FierceMonkey

Таймеры работают только в отдельном потоке, если вы настроили их для этого. Можем ли мы увидеть метод обновления заголовка и настройку таймера?
BergQuester

Я добавил запрошенный код к основному вопросу
FierceMonkey

Ответы:


208

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


16
Это действительно должен быть предпочтительный ответ. Самое простое решение. И это работает.
Йохан Карлссон

4
Согласовано. Я пробовал много других решений, и это то, что помогло само по себе.
BBQ Steve,

2
Это должен быть принятый ответ. Самое простое решение.
Machado

1
Работает как шарм! Спасибо

2
Я думаю, что это действительно хорошее решение, без написания кода для этого.
Чауян

58

Лучшим подходом, чем тот, [UIView setAnimationsEnabled:NO]который может повлиять на другие анимации, является отключение только определенной анимации заголовка.

Цель-C:

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

Swift:

UIView.performWithoutAnimation { 
    myButton.setTitle(text, for: .normal)
    myButton.layoutIfNeeded()
}

Только что попробовал решение Swift на последней версии iOS - отлично работает.
Ronen Rabinovici

1
Спаситель дня. Ура!
pkc456

Просто попробовал это в Swift 3, и он работает без использования layoutIfNeeded ()
user1898712

3
Без сомнения, это должен быть принятый ответ!
Юлий

1
Это лучший способ сделать это. Отличный ответ!
aecend

29

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

когда " buttonType " для _button равен "UIButtonTypeSystem" , приведенный ниже код недействителен

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

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


19

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

[UIView setAnimationsEnabled:NO];
[elapsed setTitle:[NSString stringWithFormat:@"%.2i:%.2i:%.2i:%.2i",days,hours,minutes,seconds] forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

7
@FierceMonkey попробуйте добавить вызов layoutIfNeeded: [elapsed layoutIfNeeded];. В моем случае это убрало мигание.
Клаас

1
layoutIfNeeded сделал это за меня.
Kaolin Fire

Кажется, это довольно грязный обходной путь, однако layoutIfNeeded, похоже, он работает
Пшемыслав

7

Вы можете просто сделать другую функцию для UIButton для облегчения использования в будущем.

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

Вот и все!

И просто установите заголовок, как и раньше, но замените setTitleнаsetTitleWithoutAnimation


6

Поведение по умолчанию "setTitle" определенно ненавистно!

Мое решение:

[UIView setAnimationsEnabled:NO];
[_button layoutIfNeeded]; 
[_button setTitle:[NSString stringWithFormat:@"what" forState:UIControlStateNormal];
[UIView setAnimationsEnabled:YES];

Кроме того, в раскадровке под свойством кнопки я снимаю флажок:

  • Переворачивает при выделении
  • Выделенное Настроить изображение

И проверьте:

  • Отключено Настроить изображение

Протестировано и работает на iOS 8 .

Обновление - Swift

Я предлагаю вам создать собственную кнопку и переопределить метод setTitle .

class UnflashingButton: UIButton {
   
    override func setTitle(title: String?, forState state: UIControlState) {
        UIView.setAnimationsEnabled(false)
        self.layoutIfNeeded()
        super.setTitle(title, forState: state)
        UIView.setAnimationsEnabled(true)
    }

}

Я пробовал этот подход (создание подклассов, переопределение setTitle: forState: и отключение-включение UIView.setAnimationsEnabled). У меня не работает в iOS 9 и 10 beta. Это сработает, если я отключу только анимацию, но тогда они теряются для каждого UIView ...
cdf1982,

2

Попробуйте это, это работает в новых версиях IOS:

class CustomButtonWithNoEffect : UIButton {
    override func setTitle(_ title: String?, for state: UIControlState) {
        UIView.performWithoutAnimation {
            super.setTitle(title, for: state)
            super.layoutIfNeeded()
        }
    }

}

0

Я новичок в кодировании и Stackoverflow, поэтому у меня недостаточно репутации, чтобы напрямую комментировать, чтобы расширить https://stackoverflow.com/users/4673064/daniel-tseng отличный ответ. Поэтому мне нужно написать свой новый ответ, и он такой:

extension UIButton {
    func setTitleWithoutAnimation(_ title: String?, for controlState: UIControlState) {
        UIView.performWithoutAnimation {
            self.setTitle(title, for: controlState)
            self.layoutIfNeeded()
        }
    }
}

Отлично работает, КРОМЕ:

Если все мои последующие вызовы в коде для «setTitleWithoutAnimation» не указывают отправителя, то я получаю эти странные сообщения, связанные с CoreMedia или CoreData, например, «Не удалось наследовать разрешения CoreMedia от 2526: (null)»

Это, вероятно, довольно просто для кодирования и iOS, но для меня, как нового кодировщика, это на какое-то время отправило меня по кроличьему следу, например: Сегодня расширение не удалось наследовать разрешения CoreMedia , где у людей были интересные ответы, но это НЕ достичь корня моей проблемы.

Итак, я наконец обнаружил, что мне нужно пройти и передать параметры моих функций без параметров, то есть мне нужно указать отправителя. Этим отправителем может быть UIButton, Any или AnyObject. Все это сработало, но в конечном итоге, похоже, возник конфликт между добавлением расширения кнопки с помощью «self» и тем, что позже конкретно не сказано, что кнопка его использует.

Опять же, вероятно, базовый, но новый для меня, поэтому я подумал, что им стоит поделиться.


0

Еще одна уловка

@IBOutlet private weak var button: UIButton! {
    didSet {
        button.setTitle(title, for: .normal)
    }
}

Это работает, только если вы знаете значение заголовка без каких-либо вызовов API. Название кнопки будет установлено до загрузки представления, поэтому вы не увидите анимацию.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.