UIButton titleLabel размер кадра, возвращающий CGSize с нулевой шириной и высотой

Для iOS7 я использовал свойство UIButton titleLabel.frame.size.width для определения ширины названия моей кнопки в разных локализации, чтобы я мог правильно позиционировать заголовок, используя contentInset на UIButton.

My UIButton настроен с изображением и названием, и я всегда хочу, чтобы комбинация этих двух была горизонтально сосредоточена в UIButton, например:

[space-x (image) space-y (titleLabel) space-x]

В iOS 7 и Xcode 5.1 следующий код работает отлично (даже работает на iOS 8 GM при построении в XCode 5.1):

CGSize buttonSize = button.frame.size;
CGSize titleSize = button.titleLabel.frame.size;
float contentInset =((buttonSize.width - (titleSize.width + 18 + 3)) / 2 );
float contentInsetRounded = roundf(contentInset);
[button setContentEdgeInsets:(UIEdgeInsetsMake(0, contentInsetRounded, 0, 0))];

(18 - ширина изображения, а 3 - количество интервалов между изображением и titleLabel или пробел-y в моем примере выше)

В iOS 8 и Xcode 6 GM button.titleLabel.frame.size возвращает CGSize с нулевой шириной и высотой, поэтому мой ContentInset заканчивает центрирование UIImage в UIButton, заставляя titleLabel усекать.

Любые идеи? Я попытался установить текст titleLabel непосредственно перед этим кодом, если он считает, что он пуст, но это тоже не помогло.

Спасибо заранее!

Ответы

Ответ 1

I разрешено. Приложение запускается на iOS8, создается с помощью Xcode 6, а не обновляет кадр сразу после UIButton setTitle, setTitleEdgeInsets. Он будет ждать следующего обновления пользовательского интерфейса. Итак, если вы получаете фреймворк titleLabel, вы получите CGRectZero.

Решение

  • Вызовите ниже методы после установки свойства пользовательского интерфейса, чтобы немедленно обновить макет:

    [self setNeedsLayout];
    [self layoutIfNeeded];

Или:

  1. Задержка секунды, и вы можете получить titleFrame, использовать self.titleLabel.frame.

Или:

  1. dispatch_async в главной очереди, чтобы переместить код в следующую очередь

Ответ 2

Задайте текст заголовка, затем сделайте sizeToFit для ярлыка заголовка и попробуйте получить названиеLabel.frame.size.width

[myButton setTitle:@"My Title" forState:UIControlStateNormal];
[myButton.titleLabel sizeToFit];

Ответ 3

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

[theButton setTitle: @"theTitle" forState:UIControlStateNormal];
[theButton setImage: theImage forState:UIControlStateNormal];
[theButton setNeedsLayout];
[theButton layoutIfNeeded];
[theButton setImageEdgeInsets: UIEdgeInsetsMake(6, transactionsButton.titleLabel.frame.size.width + 40.0, 0, 0)];

И в Swift 3 это будет делать.

self.view.layoutIfNeeded()

Ответ 4

Возможно, это не сработает для вас, но у меня была такая же проблема при запуске моего кода в XCode 6 GM/iOS8 и не удалось заставить его работать. Он работал случайным образом, и в итоге я использовал другой подход вместо NSString. Я использовал NSAttributedString в качестве заголовка.

NSMutableAttributedString *attributedText = [[NSMutableAttributedString alloc] initWithString:@"Button text"];
NSTextAttachment* textAttachment = [NSTextAttachment new];
textAttachment.image = [UIImage imageNamed:@"Arrows"];
NSAttributedString *finalString = [NSAttributedString attributedStringWithAttachment:textAttachment];
[attributedText appendAttributedString:finalString];

Только остерегайтесь того, что его iOS7 и выше, но, похоже, работают безупречно.

Ответ 5

Оказывается, я сильно передумал в этой проблеме. Я достал весь код кода содержимого, поэтому мне не нужно было найти frame.size. Теперь я просто центризую названия кнопок, и все хорошо!

Кажется, что есть проблема с получением frame.size, но для моих нужд я могу обойти это.