it-swarm.com.ru

iOS: многострочная UILabel в автоматическом макете

У меня возникли проблемы с попыткой добиться базового поведения макета с помощью Auto Layout. Мой контроллер вида выглядит так в IB:

enter image description here

Верхний ярлык - это заголовок, я не знаю, сколько будет строк. Мне нужен заголовок для отображения всех строк текста. Мне также нужны два других ярлыка и маленькое изображение, которое должно быть расположено прямо под заголовком, каким бы высоким оно ни было. Я установил ограничения по вертикали между метками и маленьким изображением, а также ограничение по верхнему интервалу между меткой заголовка и его суперпредставлением и ограничение по нижнему интервалу между маленьким изображением и его суперпредставлением. Белый UIView не имеет ограничения по высоте, поэтому он должен растягиваться вертикально, чтобы содержать его подпредставления. Я установил количество строк для заголовка на 0.

Как я могу изменить размер заголовка, чтобы он соответствовал количеству строк, требуемому для строки? Насколько я понимаю, я не могу использовать методы setFrame, потому что я использую Auto Layout. И я должен использовать Auto Layout, потому что мне нужно, чтобы эти другие представления оставались ниже метки заголовка (отсюда и ограничения).

Как я могу это сделать?

177
James Harpe

Используйте -setPreferredMaxLayoutWidth для UILabel, а autolayout должен обрабатывать все остальное.

[label setPreferredMaxLayoutWidth:200.0];

См. документация UILabel для предпочитаемого MaxLayoutWidth .

Обновление:

Нужно только установить ограничение высоты в раскадровке на значение "Больше или равно", нет необходимости устанавливать setPreferredMaxLayoutWidth.

248
mwhuss

Увеличьте количество строк в вашем наборе меток до 0, а также, что более важно, для автоматической установки высоты макета до> = x. Авто макет сделает все остальное. Вы также можете содержать другие элементы, основанные на предыдущем элементе, чтобы затем правильно расположить.

auto layout

210
Charlie Wu

Источник: http://www.objc.io/issue-3/advanced-auto-layout-toolbox.html

Размер внутреннего содержимого многострочного текста

Размер внутреннего содержимого UILabel и NSTextField неоднозначен для многострочного текста. Высота текста зависит от ширины линий, которая еще не определена при решении ограничений. Чтобы решить эту проблему, у обоих классов есть новое свойство предпочитаемое значение AdditionalMaxLayoutWidth, которое определяет максимальную ширину линии для расчета размера внутреннего содержимого.

Поскольку мы обычно не знаем этого значения заранее, нам нужно сделать два шага, чтобы получить это право. Сначала мы позволяем Auto Layout выполнять свою работу, а затем используем результирующий кадр на этапе макета, чтобы обновить предпочтительную максимальную ширину и снова запустить макет.

- (void)layoutSubviews
{
    [super layoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [super layoutSubviews];
}

Первый вызов [super layoutSubviews] необходим для метки, чтобы получить набор фреймов, а второй вызов необходим для обновления макета после изменения. Если мы пропускаем второй вызов, мы получаем ошибку NSInternalInconsistencyException, потому что мы внесли изменения в проход макета, которые требуют обновления ограничений, но мы больше не запускаем макет.

Мы также можем сделать это в самом подклассе меток:

@implementation MyLabel
- (void)layoutSubviews
{
    self.preferredMaxLayoutWidth = self.frame.size.width;
    [super layoutSubviews];
}
@end

В этом случае нам не нужно сначала вызывать [super layoutSubviews], потому что когда вызывается layoutSubviews, у нас уже есть рамка на самой метке.

Чтобы сделать эту настройку с уровня контроллера представления, мы подключаемся к viewDidLayoutSubviews. На этом этапе кадры первого прохода Auto Layout уже установлены, и мы можем использовать их для установки предпочтительной максимальной ширины.

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    myLabel.preferredMaxLayoutWidth = myLabel.frame.size.width;
    [self.view layoutIfNeeded];
}

Наконец, убедитесь, что у вас нет явного ограничения высоты надписи, которая имеет более высокий приоритет, чем приоритет сопротивления сжатия содержимого надписи. В противном случае он превзойдет расчетную высоту содержимого. Обязательно проверьте все ограничения, которые могут повлиять на высоту надписи.

44
Anton Matosov

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

Вот ключ: Интерфейсный Разработчик любит добавлять дополнительные ограничения, когда вы добавляете и перемещаете представления, и вы можете не заметить. В моем случае, у меня было представление на полпути вниз, которое имело дополнительное ограничение, определяющее размер между ним и его суперпредставлением, в основном привязывая его к этой точке. Это означало, что ничто над этим не могло измениться больше, потому что это пошло бы против этого ограничения.

Простой способ определить, так ли это, - попытаться изменить размер метки вручную. Позволяет ли IB это выращивать? Если это так, то метки ниже перемещаются, как вы ожидаете? Убедитесь, что вы оба проверили, прежде чем изменять размер, чтобы увидеть, как ваши ограничения будут перемещать ваши представления

IB Menu

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

16
Cory Imdieke

Я считаю, что вам нужно следующее:

  • Верхнее ограничение
  • Ведущее ограничение (например, левая сторона)
  • Трейлинг-ограничение (например, правая сторона)
  • Установите приоритет размещения контента, горизонтальный на низкий, чтобы он занимал заданное пространство, если текст короткий.
  • Установите сопротивление сжатию содержимого, горизонтальное на низкое, чтобы оно не перекрывалось, а пыталось расширяться.
  • Установите количество строк в 0.
  • Установите режим разрыва строки на перенос слов.
5
Chris

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

Я нашел способ сделать это:

Установив ограничения для вашей метки и установив для его свойства multiline значение 0, создайте подкласс UILabel; Я назвал мой AutoLayoutLabel:

@implementation AutoLayoutLabel

- (void)layoutSubviews{
    [self setNeedsUpdateConstraints];
    [super layoutSubviews];
    self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}

@end
0
Tanguy G.

У меня есть UITableViewCell, который имеет текстовую метку переноса. Я работал над переносом текста следующим образом.

1) Установите ограничения UILabel следующим образом.

enter image description here

2) Установить № строк до 0.

3) Добавлено ограничение высоты UILabel в UITableViewCell.

@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!

4) На UITableViewCell:

priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
0
A.G