Текст заголовка UIButton не обновляется, даже если я обновляю его в основном потоке

Я пытаюсь изменить заголовок UIButton, который я создал программно, когда пользователь щелкает его. Итак, это мой код для создания UIButton:

myButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, parentView.frame.size.width, parentView.frame.size.height)];
[myButton setBackgroundColor:[UIColor blackColor]];
[myButton setAlpha:0.7];
[myButton setTitle:@"Hello" forState:UIControlStateNormal];
[myButton addTarget:self action:@selector(userClicked:) forControlEvents:UIControlEventTouchUpInside];

[parentView addSubview:myButton];

И в моем методе userClicked: я делаю:

-(void) userClicked:(UIButton*)button
{
    NSLog(@"USER CLICKED!!!");
    if ([NSThread isMainThread])
    {
        NSLog(@"is main thread");
    }

    [button setTitle:@"Bye" forState:UIControlStateHighlighted];
    [button setTitle:@"Bye" forState:UIControlStateNormal];
    [button setTitle:@"Bye" forState:UIControlStateSelected];

    [self someLengthyComputation];
}

Странно то, что я вижу напечатанные сообщения журнала:

USER CLICKED!!! 
isMainThread

Но название кнопки не меняется! Что я делаю неправильно?

РЕДАКТИРОВАТЬ: установка заголовка для нескольких состояний также не работает.

EDIT2: если я напечатаю описание кнопки в окне отладчика Xcode, оно покажет правильный заголовок!

Printing description of button->_titleView:
<UIButtonLabel: 0xa4c9310; frame = (95 216; 130 22); text = 'Bye'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0xa44f080>>

person neutrino    schedule 14.11.2013    source источник
comment
Возможно, ваша кнопка не находится в состоянии UIControlStateNormal?   -  person user1567896    schedule 14.11.2013
comment
Где вы добавили кнопку в качестве подвида?   -  person Vishwa Patel    schedule 14.11.2013
comment
Что такое parentView..?   -  person Anand Suthar    schedule 14.11.2013
comment
@AnandK parentView является основным UIView из UIViewController   -  person neutrino    schedule 14.11.2013
comment
@VishwaPatel См. ответ AnandK, пожалуйста.   -  person neutrino    schedule 14.11.2013
comment
@user1567896 user1567896 Позвольте мне попробовать...   -  person neutrino    schedule 14.11.2013
comment
@ user1567896 Вы были правы! Он находится в состоянии UIControlStateHighlited!   -  person neutrino    schedule 14.11.2013
comment
Но даже если я установлю заголовок для UIControlStateNormal, UIControlStateSelected и UIControlStateHighlighted, заголовок не изменится. Я обновлю свой вопрос своим фактическим кодом.   -  person neutrino    schedule 14.11.2013


Ответы (24)


Это сработало для меня, чтобы обновить текст заголовка (iOS 7.1, Xcode 5.1):

button.enabled = FALSE;
[button setTitle:@"Test" forState:UIControlStateNormal];
button.enabled = TRUE;
person Walter Schurter    schedule 20.03.2014
comment
ничего, кроме этого трюка не сработало для меня. он перестал обновлять заголовок, так как я переключился на XCode5.1/iOS7.1. это ооочень раздражает. - person Boris Gafurov; 18.04.2014
comment
Кажется, это известная ошибка в iOS7.1 SDK. prod.lists.apple.com/archives/cocoa- dev/2014/Mar/msg00274.html - person Ramon Poca; 28.04.2014
comment
Это действительно заставило меня захотеть проткнуть монитор кулаком. Отличный улов. - person rmigneco; 11.06.2014
comment
Точно такая же проблема с iOS 7.1 и Xcode 5. Отличный улов. Один досадный баг! - person Robert J. Clegg; 22.07.2014
comment
Была такая же проблема, но использование layoutSubviews, похоже, решило ее. - person Saltymule; 06.10.2014
comment
Это происходило только со мной на iOS 7, и это исправило это. Спасибо. - person Gabriel Cartier; 17.12.2014
comment
Использование setTitle вместо button.titleLabel.text сработало для меня. - person J2N; 24.08.2016

У меня была та же проблема, и я заметил, что везде я устанавливал атрибут attributeTitle. Таким образом, любые обновления заголовка не влияли на атрибутированный заголовок.

Мое решение:

[button setAttributedTitle:@"" forState:UIControlStateNormal];

вместо

[button setTitle:@"" forState:UIControlStateNormal];
person Jeffrey Sun    schedule 16.06.2014
comment
Это было проблемой для меня: я ссылался на заголовок кнопки, используя атрибутивную строку ранее, чтобы настроить отслеживание, и он больше не будет обновляться, если я просто использую setTitle. Обратите внимание, что вы не можете передать простую строку, вам нужно что-то вроде этого: [_myButton setAttributedTitle:[[NSAttributedString alloc] initWithString:@Новый заголовок для атрибутов кнопки:nil] forState:UIControlStateNormal]; - person CraicDesign; 06.12.2014
comment
Я использую XCode 9.4.1/swift, и у меня была такая же проблема. setAttributedTitle был единственным решением, которое сработало для меня. - person budiDino; 01.10.2018

На данный момент самая короткая работа, с которой я пришел, это вызов:

[button setNeedsLayout];

После обновления заголовка.

Кажется, это происходит в iOS 7.1. Все мои кнопки, которые работали правильно в предыдущих версиях iOS (или, может быть, просто скомпилированы с предыдущими SDK), внезапно перестали делать это при компиляции в Xcode 5.1.1 SDK 7.1.

Похоже на баг Apple.

person Lukasz    schedule 02.06.2014
comment
верно. [кнопка setNeedsLayout] добьется цели в iOS 7.1 - person Deepak Thakur; 22.10.2014
comment
Это все еще требуется для меня в iOS 9.2 - person Charlie Martin; 22.12.2015

У меня была аналогичная проблема с использованием раскадровки. Используя ответы выше, мне пришлось использовать

[mybutton setTitle:@"SomeText" forState:UIControlStateNormal];
[button setNeedsLayout];
[button layoutIfNeeded];

И я должен был убедиться, что тип кнопки был «Пользовательский», а не «Системный» в инспекторе атрибутов.

person user3000868    schedule 09.01.2015
comment
С этим И ... комментарием вы спасли мой день !!! Спасибо. Вот и все — никогда не забывайте настраивать кнопку в раскадровке, когда создаете подкласс, иначе поведение может быть странным. - person Vilém Kurz; 06.10.2016
comment
Спасибо спасибо спасибо. Я сломал голову за последнюю неделю. Ваша часть И сделала мой день .. - person Swayambhu; 08.02.2017
comment
Мне нужно было только установить тип Custom, мне не нужно было добавлять setNeedsLayout или layoutIfNeeded. - person christophercotton; 31.05.2017
comment
Спасибо, вы спасли мой день, указав на стиль кнопки в раскадровке! На самом деле моя проблема заключалась в том, что стиль кнопки, установленный в раскадровке, был Системным, а не Пользовательским :) - person Eugenio; 19.06.2018
comment
[кнопка setNeedsLayout]; и [раскладка кнопки, если нужно]; это одно и то же, за исключением одного отличия. Первый работает асинхронно, а второй работает синхронно. Так что любой из них работает нормально, - person Rehan Ali; 05.08.2018

Пожалуйста, посмотрите, может ли это вам помочь... при нажатии кнопки проверьте условие if buttonToggled... как показано ниже, когда у вас есть такая функция, как changeButtonText

-(IBAction)changeButtonText:(id)sender {
    if (!buttonToggled) {
        [sender setTitle:@"Initial Text" forState:UIControlStateNormal];
        buttonToggled = YES;
    } else {
        [sender setTitle:@"Alternative Text" forState:UIControlStateNormal];
        buttonToggled = NO;
    }
}
person bachman    schedule 14.11.2013

В вашем коде есть несколько проблем:

Вы назначаете обратный вызов на кнопку:

@selector(userClicked:)

но ваш код находится в другом методе:

-(void)userTapOnTapToRefreshView:(UIButton*)button

Чтобы исправить это, вам нужно реализовать что-то вроде этого:

-(void)userClicked:(id)sender
{
    [(UIButton*)sender setTitle:@"Bye" forState:UIControlStateNormal];
}

Также эта часть кода не имеет смысла для меня:

[parentView myButton];

Попробуйте изменить его на:

[parentView addSubview:myButton];

Надеюсь поможет :)

person Eugene Tartakovsky    schedule 14.11.2013
comment
Большое спасибо за ваш ответ. На самом деле, все эти ошибки были сделаны мной, когда я пытался сократить свой реальный код, чтобы опубликовать здесь свой вопрос. Я отредактировал свой исходный пост, чтобы показать правильный код с указанными вами изменениями. - person neutrino; 14.11.2013

Для Swift 3 до 5 просто используйте следующее:

button.setTitle("My title", for: .normal)

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

button.setAttributedTitle(<AttributedString>, for: .normal)
person zero3nna    schedule 22.03.2017

Это довольно поздно и в некоторой степени связано с ответом Уолтера Шуртера:

У меня была похожая проблема, когда текст моей кнопки устанавливался правильно, пока я не обновился до 7.1. Затем я обнаружил, что, поскольку моя кнопка была отключена, мне пришлось установить цвет заголовка и текст заголовка для отключенного состояния, чтобы текст отображался. Тогда все работало как шарм!

person dragonflyesque    schedule 09.04.2014

В iOS 7 заголовок UIButton не обновляется, когда он отключен. Похоже на ошибку iOS 7.

В качестве обходного пути обновите как обычный, так и отключенный заголовок. Оно работает!

[button setTitle:title forState:UIControlStateNormal];
[button setTitle:title forState:UIControlStateDisabled];
person ccoroom    schedule 06.03.2015
comment
Я люблю тебя @ccoroom. Спас мою ночь. - person John Doe; 12.07.2015
comment
Также вы можете написать в одну строку следующим образом: [button setTitle:title forState:UIControlStateNormal | UIControlStateDisabled]; - person Bohdan Savych; 29.08.2016

Попробуй это:

[button setTitle:@"Bye" forState:UIControlStateHighlighted];

or:

[button setTitle:@"Bye" forState:UIControlStateSelected];

Вы также можете изменить свою функцию void:

-(void) userClicked
{
    NSLog(@"USER CLICKED!!!");
    if ([NSThread isMainThread])
    {
        NSLog(@"is main thread");
    }

    [myButton setTitle:@"Bye" forState:UIControlStateNormal];
}
person Nikos M.    schedule 14.11.2013
comment
Спасибо! [button setTitle:@"Bye" forState:UIControlStateHighlighted]; сделал свое дело! - person neutrino; 14.11.2013
comment
Хорошо, моя ошибка, даже если я устанавливаю заголовок для UIControlStateNormal, UIControlStateSelected и UIControlStateHighlighted, заголовок не меняется. Я обновлю свой вопрос своим фактическим кодом. - person neutrino; 14.11.2013
comment
Отредактировал и мой ответ. Объявите myButton как свойство, чтобы вы могли ссылаться на него в функции void. - person Nikos M.; 14.11.2013
comment
не работает :(, проблема не связана с mainthread, потому что вы можете обновить кнопку, если вы не перешли к другому контроллеру Uiview - person Amr Angry; 21.08.2016

В моем случае я пробовал все, но ничего не работало. Затем я просто изменил тип кнопки с системного на пользовательский из раскадровки. БУМ! все стало вести себя нормально.

person Siddhesh Mahadeshwar    schedule 27.04.2016

Измените тип кнопки на «Пользовательский» вместо «Системный», и он будет работать как положено :)

person Pulkit Arora    schedule 04.02.2017

Ну, это все о включенном состоянии UIButton, Apple что-то изменила в 7.1, что не позволяет вам изменить заголовок, если у вас есть UIButton в отключенном состоянии, вот и все.

Спасибо Apple, я потерял 10 минут. отладка приложения, которое работало нормально.

Только что узнал сегодня утром, вчера обновил XCode до 5.1.1 и iOS до 7.1.

person Kiko Seijo    schedule 08.05.2014

Это может быть проблема с обновлением макета кнопки..... Попробуйте использовать...

[button setNeedsLayout];
[button layoutIfNeeded];

Это заставит кнопку обновить макет.

person iOSGuest    schedule 14.10.2014

Наконец, я понял это. Было две проблемы:

1) button не был в состоянии UIControlStateNormal.

2) Я вызывал метод, выполняющий долгие вычисления сразу после установки заголовка [self someLengthyComputation].

Я решил проблему:

1) Установка заголовка для всех состояний кнопки.

2) Выполнение этого большого вычисления в другом потоке, а не в основном потоке.

Мой рабочий код сейчас:

-(void) userClicked:(UIButton*)button
{
    NSLog(@"USER CLICKED!!!");
    if ([NSThread isMainThread])
    {
        NSLog(@"is main thread");
    }

    [button setTitle:@"Bye" forState:UIControlStateHighlighted];
    [button setTitle:@"Bye" forState:UIControlStateNormal];
    [button setTitle:@"Bye" forState:UIControlStateSelected];
    dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
        [self someLengthyComputation];
    });
}

Большое спасибо всем, кто ответил/комментировал!

person neutrino    schedule 14.11.2013
comment
не работает :(, проблема не связана с mainthread, потому что вы можете обновить кнопку, если вы не перешли к другому контроллеру Uiview - person Amr Angry; 21.08.2016

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

person dobranoc    schedule 19.01.2016

Согласно руководству разработчика Apple, вы не должны устанавливать текст или цвет метки заголовка кнопки непосредственно в качестве свойства (например, не делайте это: myButton.titleLabel.text=@"SomeText" или myButton. titleLabel.textColor=[UIColor blackColor]).

Скорее, вы устанавливаете их с помощью функции установки UIButton, например:

    [myButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];

... или вот так:

    [myButton setTitle:@"SomeText" forState:UIControlStateNormal];.

См. руководство Apple< /а>.

person Epsilon3    schedule 13.06.2014
comment
Не тогда, когда я разместил свой ответ. - person Epsilon3; 18.08.2016
comment
Ах, есть ли какой-то способ, которым мы могли бы это сказать? - person calql8edkos; 18.08.2016

Вывод после перебора многих решений — использовать setAttributedTitle вместо setTitle.

Чтобы сделать строку заголовка для AttributedString:

NSMutableAttributedString *attString = [[NSMutableAttributedString alloc] initWithString:@" new Test "];

[button setAttributedTitle:attString forState:UIControlStateNormal];

Кстати, эта проблема не случается в норме, а внезапно возникает в основном по следующим причинам:

  1. Если вы измените включенное состояние UIButton и попытаетесь изменить заголовок.

  2. Если вы используете атрибутивное значение, а затем хотите изменить его с помощью setTitle, в этом случае атрибутивное значение превосходит заголовок.

  3. Если вы перейдете к другому контроллеру представления, а затем вернетесь назад, чтобы обновить заголовок кнопки.

person Amr Angry    schedule 22.08.2016

Нет необходимости использовать:

[button setNeedsLayout];
[button layoutIfNeeded];

Вместо этого сначала установите тип ПО УМОЛЧАНИЮ на ПОЛЬЗОВАТЕЛЬСКИЙ.

Если вы применили setAttributedTitle, используйте:

[button setAttributedTitle:[NSAttributedString new] forState:UIControlStateNormal];

В противном случае нет необходимости что-либо менять.

Если цвет текста не изменился, примените то же самое и установите цвет заголовка с помощью:

[button setTitleColor:[any_color] forState:UIControlStateNormal];
person jenish    schedule 23.07.2016

Ничего из вышеперечисленного не работало в моем случае (у меня была кнопка поверх представления, представленного с помощью UIPopoverController), и мне пришлось удалитьFromSuperview перед setTitle, а затем добавитьSubview обратно - надеюсь, это поможет кому-то с похожими проблемами

person hyouuu    schedule 11.06.2017

Я сомневаюсь, что «кнопка», переданная в качестве параметра, является myButton. В любом случае, если myButton является членом var, вы можете просто [myButton setTitle:@"Bye" forState:UIControlStateNormal];

person Hunter    schedule 14.11.2013
comment
Я проверил это, и кнопка фактически равна myButton. Проблема была в состоянии кнопки. Смотрите принятый ответ. В любом случае, спасибо! - person neutrino; 14.11.2013
comment
Я думал, вы навсегда измените текст после нажатия на кнопку. В любом случае, поздравляю. - person Hunter; 14.11.2013

Попробуйте объявить свою кнопку как свойство либо в интерфейсе, либо в части реализации вашего контроллера представления/представления.

@property(nonatomic,strong) UIButton* myButton;

затем создайте его

self.myButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, parentView.frame.size.width, parentView.frame.size.height)];
[_myButton setBackgroundColor:[UIColor blackColor]];
...

Он должен работать. Не спрашивайте меня, почему на самом деле - я просто думаю, что все дело в ARC/современном управлении памятью.

ИЗМЕНИТЬ:

Это также должно работать, если вы сохраните ссылку на кнопку в своей реализации.

@implementation myViewController
{
    UIButton* myButton;
}

-(void)createButton
{
    myButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, parentView.frame.size.width, parentView.frame.size.height)];
    [myButton setBackgroundColor:[UIColor blackColor]];
    ...
}

...
person Moose    schedule 05.09.2016

вместо yourButton.titleLabel?.text = "T"

используйте это yourButton.setTitle("TITLE", for: .normal)

person Divyanshu Kumar    schedule 23.10.2018

Всегда делайте addSubview перед установкой текста на UIButton.

person PPVZ    schedule 03.09.2014
comment
Можете ли вы опубликовать код, чтобы проиллюстрировать, что вы имеете в виду? - person DanM7; 04.09.2014
comment
Мы не можем понять, что вы имеете в виду. - person ondermerol; 23.01.2017