iOS: многострочная UILabel в автоматическом макете
У меня возникли проблемы с попыткой добиться базового поведения макета с помощью Auto Layout. Мой контроллер вида выглядит так в IB:
Верхний ярлык - это заголовок, я не знаю, сколько будет строк. Мне нужен заголовок для отображения всех строк текста. Мне также нужны два других ярлыка и маленькое изображение, которое должно быть расположено прямо под заголовком, каким бы высоким оно ни было. Я установил ограничения по вертикали между метками и маленьким изображением, а также ограничение по верхнему интервалу между меткой заголовка и его суперпредставлением и ограничение по нижнему интервалу между маленьким изображением и его суперпредставлением. Белый UIView не имеет ограничения по высоте, поэтому он должен растягиваться вертикально, чтобы содержать его подпредставления. Я установил количество строк для заголовка 0.
Как я могу изменить размер заголовка, чтобы он соответствовал количеству строк, требуемому для строки? Насколько я понимаю, я не могу использовать методы setFrame, потому что я использую Auto Layout. И я должен использовать Auto Layout, потому что мне нужно, чтобы эти другие представления оставались ниже метки заголовка (отсюда и ограничения).
Как я могу сделать это?
8 ответов
Использование -setPreferredMaxLayoutWidth
на UILabel
и autolayout должен обрабатывать все остальное.
[label setPreferredMaxLayoutWidth:200.0];
Смотрите документацию UILabel.
ОБНОВИТЬ:
Нужно только установить ограничение высоты в раскадровке на значение "Больше или равно", нет необходимости устанавливать setPreferredMaxLayoutWidth.
Увеличьте количество строк в вашем наборе меток до 0, а также, что более важно, для высоты набора автоматического макета до>= x. Авто макет сделает все остальное. Вы также можете содержать другие элементы, основанные на предыдущем элементе, чтобы затем правильно расположить.
Источник: 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];
}
Наконец, убедитесь, что у вас нет явного ограничения высоты надписи, которая имеет более высокий приоритет, чем приоритет сопротивления сжатия содержимого надписи. В противном случае он превзойдет расчетную высоту содержимого. Обязательно проверьте все ограничения, которые могут повлиять на высоту метки.
Я только боролся с этим точным сценарием, но с довольно большим количеством представлений, которые должны были изменить размер и сместиться по мере необходимости. Это сводило меня с ума, но я наконец понял это.
Вот ключ: Интерфейсный Разработчик любит добавлять дополнительные ограничения, когда вы добавляете и перемещаете представления, и вы можете не заметить. В моем случае, у меня было представление на полпути вниз, в котором было дополнительное ограничение, определяющее размер между ним и его суперпредставлением, в основном привязывая его к этой точке. Это означало, что ничто выше этого не могло измениться больше, потому что это пошло бы против этого ограничения.
Простой способ определить, так ли это, - попытаться изменить размер метки вручную. Позволяет ли IB расти? Если это так, то метки ниже двигаются так, как вы ожидаете? Убедитесь, что вы оба проверили, прежде чем изменять размер, чтобы увидеть, как ваши ограничения будут перемещать ваши представления:
Если представление застряло, следуйте за представлениями, которые находятся ниже него, и убедитесь, что у одного из них нет верхнего пространства для ограничения суперпредставления. Затем просто убедитесь, что параметр количества строк для метки установлен на 0, и он должен позаботиться об остальном.
Я считаю, что вам нужно следующее:
- Верхнее ограничение
- Ведущее ограничение (например, левая сторона)
- Трейлинг-ограничение (например, правая сторона)
- Установите приоритет размещения контента, горизонтальный на низкий, чтобы он занимал заданное пространство, если текст короткий.
- Установите сопротивление сжатию содержимого, горизонтальное на низкое, чтобы оно было обернуто, а не стало шире.
- Установите количество строк в 0.
- Установите режим разрыва строки на перенос слов.
У меня есть UITableViewCell, который имеет текстовую метку переноса. Я работал над переносом текста следующим образом.
1) Установите ограничения UILabel следующим образом.
2) Установить № строк до 0.
3) Добавлено ограничение высоты UILabel в UITableViewCell.
@IBOutlet weak var priorityLabelWidth: NSLayoutConstraint!
4) На UITableViewCell:
priorityLabel.sizeToFit()
priorityLabelWidth.constant = priorityLabel.intrinsicContentSize().width+5
Ни одно из различных решений, найденных во многих темах по теме, не подошло идеально для моего случая (x динамических многострочных меток в ячейках динамического табличного представления) .
Я нашел способ сделать это:
Установив ограничения для вашей метки и установив для его свойства multiline значение 0, создайте подкласс UILabel; Я назвал мой AutoLayoutLabel:
@implementation AutoLayoutLabel
- (void)layoutSubviews{
[self setNeedsUpdateConstraints];
[super layoutSubviews];
self.preferredMaxLayoutWidth = CGRectGetWidth(self.bounds);
}
@end
Один из способов сделать это... Когда длина текста увеличивается, попробуйте изменить (уменьшить) размер шрифта текста надписи, используя
Label.adjustsFontSizeToFitWidth = YES;