Как остановить нежелательную анимацию 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" выше код действительный.
в 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 должен быть похожим)
вы можете просто создать пользовательскую кнопку, и она перестанет анимироваться при изменении заголовка.
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setTitle:@"the title" forState:UIControlStateNormal];
вы также можете сделать это в поле раскадровки : выберите кнопку в раскадровке - > выберите инспектор атрибутов (четвертый слева) -> в раскрывающемся меню " тип "выберите" пользовательский "вместо " система", которая, вероятно, была выбрана.
удачи!
вы можете удалить анимацию из слоя метки заголовка:
[[[theButton titleLabel] layer] removeAllAnimations];
обычно просто установка типа кнопки на пользовательские работы для меня, но по другим причинам мне нужно было подкласс 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)
}
}
}