Как я могу использовать Autolayout для создания макета, который расширяется по высоте на основе содержимого UILabel

Я пытаюсь создать динамический макет, используя новый API-интерфейс autolayout в iOS 6.0. Макет, который я пытаюсь построить, имеет 2 кнопки с меткой между ними, как показано на рисунке ниже:

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

Я бы хотел, чтобы представление контейнера, показанное серым цветом, увеличивалось или уменьшалось в размере в зависимости от количества текста в метке.

До сих пор мне удавалось заставить макет работать точно так, как описано, с одной небольшой проблемой, которую я не смог решить. Проблема, с которой я сталкиваюсь, заключается в том, что внутренняя высота метки всегда рассчитывается с использованием исходной ширины метки (например, той, что установлена ​​в построителе интерфейса), а не ширины метки, которая устанавливается из ограничений, которые у меня есть на нем.

Ограничения, которые у меня есть для представлений, следующие:

  • H:|-[левая кнопка]-[метка]-[правая кнопка]-|
  • Обе кнопки центрированы по вертикали
  • V: |-[метка]-|
  • приоритет содержимого кнопок выше, чем метка
  • Сопротивление сжатию этикетки выше, чем у контейнера вида

Все эти ограничения вместе создают желаемый макет.

Однако:

  • Если ширина метки в построителе интерфейса (литеральный размер в построителе интерфейса) меньше ширины представления во время выполнения, то высота контейнера слишком велика.

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

Чтобы прояснить это, представление IB приведенного выше макета было следующим (обратите внимание, что оно намного уже):

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

  • Если ширина метки в построителе интерфейса (литеральный размер в построителе интерфейса) больше, чем ширина представления во время выполнения, то высота контейнера слишком мала, и строки текста обрезаются.

Похоже, что происходит то, что, хотя ограничений на ширину метки нет, метка, похоже, вычисляет свою высоту (и, следовательно, вычисляемую автомакетом высоту контейнера) на основе исходной ширины метки при ее создании. Однако что так странно, так это то, что текст имеет правильную ширину и высоту, но сама этикетка имеет рамку, которая слишком велика или мала.

Я предполагаю, что это связано с порядком, в котором происходят вещи, и попытался вызвать updateConstraintsIfNeeded в методе layoutSubview containerViews, однако это, похоже, ничего не делает.

Любые предложения будут ценны.


person Duncan    schedule 21.09.2012    source источник


Ответы (3)


Может быть, я опоздал, но в любом случае я нашел решение. Каждый раз, когда изменяется ширина метки, вам необходимо вручную обновить PreferredMaxLayoutWidth для метки. Например:

Label.preferredMaxLayoutWidth = 200;

Конструктор интерфейса задает PreferredMaxLayoutWidth с начальной шириной метки. Надеюсь это поможет.

person Mark Kryzhanouski    schedule 18.12.2012

Вы пытались вызвать -invalidateIntrinsicContentSize на своем ярлыке?

person Jon Hull    schedule 26.09.2012
comment
Спасибо за предложение, к сожалению, да. Я попытался вызвать invalidateIntrinsicContentSize в нескольких местах, наиболее логичным оказалось в layoutSubviews. Я думаю, что метка вычисляет свой внутренний размер и снова вызывает недействительность, просто снова возвращает тот же размер. - person Duncan; 27.09.2012
comment
Вы можете попробовать зарегистрироваться, чтобы получать уведомления об изменении текста поля и вызывать его там. Кажется, это работает для текстовых полей и меток (хотя я еще не пробовал это в текстовом представлении). - person Jon Hull; 28.09.2012
comment
или, скорее, я еще не пробовал его на чем-то, что занимает более одной строки. Это определенно работает для ширины одной строки, хотя... - person Jon Hull; 28.09.2012

Да, для этого также можно использовать -invalidateIntrinsicContentSize.

  1. Создайте пользовательский класс, например CustomLabel.
  2. Установите этот класс для UILabel в построителе интерфейса.
  3. Переопределите функции, которые возвращают IntrinsicContentSize.

    -(CGSize)intrinsicContentSize {
    //If the width is Zero.
    if (self.frame.size.width == 0) {
        return [super intrinsicContentSize];
    }
    
    return [self.text sizeWithFont:self.font constrainedToSize:CGSizeMake(self.frame.size.width, MAXFLOAT)];
    }
    
  4. Сообщите системе, чтобы пересчитать ее внутренний размер, вызвав метод. [CustomLabel invalidateIntrinsicContentSize];

Надеюсь, это поможет.

person Asif Bilal    schedule 24.02.2014