UILabel в UITableViewCell с автоматической компоновкой имеет неправильную высоту
У меня есть UITableView
с ячейками с фиксированной высотой 100 точек. Ячейки создаются в файле xib, который использует 3 ограничения для привязки UILabel
к левому, правому и верхнему краям ячейки contentView
. Приоритет вертикального обхода ярлыка установлен в 1000, потому что я хочу, чтобы высота ячейки была как можно меньше.
Когда ширина ячейки в файле xib установлена в 320 точек, то же, что и ширина таблицыView на iPhone, автозапуск работает, как ожидалось. Однако, когда я устанавливаю ширину ячейки до менее 320 точек, я получаю неожиданные результаты. (Я хочу использовать одну и ту же ячейку в таблицах, имеющих разную ширину, например, в универсальном приложении)
Например: когда я устанавливаю ширину на 224 точки и даю ярлыку текст, который занимает две строки с такой шириной, высота надписи будет увеличиваться, чтобы соответствовать двум строкам, но когда ячейка затем будет изменена до 320 точек чтобы поместиться в tableView этой ширины, текст занимает только одну строку, но высота метки остается на 2 строках.
Я поставил образец проекта на GitHub, чтобы продемонстрировать проблему: https://github.com/bluecrowbar/CellLayout
Есть ли способ изменить размер UILabel
, чтобы обнять его текстовый контент?
Ответы
Ответ 1
Добавление этого в подклассу ячейки работает:
- (void)layoutSubviews
{
[super layoutSubviews];
[self.contentView layoutIfNeeded];
self.myLabel.preferredMaxLayoutWidth = self.myLabel.frame.size.width;
}
Я нашел это на http://useyourloaf.com/blog/2014/02/14/table-view-cells-with-varying-row-heights.html.
Обновление 1: этот ответ был для iOS 7. Я считаю, что автоматический макет в ячейках таблицы выглядит очень ненадежным с iOS 8, даже для очень простых макетов. После много экспериментов я (в основном) вернулся к выполнению ручной компоновки и ручному вычислению высоты ячейки.
Обновление 2: Я запускал несколько тестов на iOS 9, и кажется, что UITableViewAutomaticDimension
, наконец, работает как рекламируемый. Ура!
Ответ 2
Глупая ошибка! Я потерял почти один день в этой проблеме, и, наконец, я решил это с решением Стивена Вандеге.
Быстрая версия:
override func layoutSubviews() {
super.layoutSubviews()
self.contentView.layoutIfNeeded()
self.myLabel.preferredMaxLayoutWidth = self.myLabel.frame.size.width
}
Ответ 3
Поскольку вы сдерживаете метку width
, intrinsicContentSize
отмечает, что width
и настраивает height
. И это создает проблему с курицей и яйцом:
- Результат автоматической компоновки ячейки зависит от метки
intrinsicContentSize
- Метка
intrinsicContentSize
зависит от метки width
- Метка
width
зависит от результата автоматической компоновки ячейки
Итак, происходит то, что компоновка ячейки вычисляется только один раз, когда (2) основывается на статической ширине в XIB файле, и это приводит к неправильной метке height
.
Вы можете решить это, итерации. То есть, повторите вычисление автоматического макета после того, как метка width
была установлена первым вычислением. Что-то вроде этого в вашей пользовательской ячейке будет работать:
- (void)drawRect:(CGRect)rect
{
CGSize size = self.myLabel.bounds.size;
// tell the label to size itself based on the current width
[self.myLabel sizeToFit];
if (!CGSizeEqualToSize(size, self.myLabel.bounds.size)) {
[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
}
[super drawRect:rect];
}
оригинальное решение не работает надежно:
- (void)layoutSubviews
{
[super layoutSubviews];
// check for need to re-evaluate constraints on next run loop
// cycle after the layout has been finalized
dispatch_async(dispatch_get_main_queue(), ^{
CGSize size = self.myLabel.bounds.size;
// tell the label to size itself based on the current width
[self.myLabel sizeToFit];
if (!CGSizeEqualToSize(size, self.myLabel.bounds.size)) {
[self setNeedsUpdateConstraints];
[self updateConstraintsIfNeeded];
}
});
}
Ответ 4
Я обычно добавляю эти две строки в viewDidLoad()
self.tableView.rowHeight = UITableViewAutomaticDimension
self.tableView.estimatedRowHeight = 96
Это автоматически изменит размер ячейки
Ответ 5
Я использую XCode 10 с iOS 12, и у меня все еще возникают проблемы с автоматическим размещением, когда ячейки не получают правильную высоту при первом представлении таблицы. Ответ Тимоти Муса не решил для меня проблему, но на основе его объяснения я нашел решение, которое действительно работает для меня.
Я создаю подкласс UITableViewController и перезаписываю сообщение viewDidLayoutSubviews, чтобы проверить изменения ширины, а затем принудительно обновляю таблицу, если ширина действительно изменяется. Это устраняет проблему до того, как представление будет представлено, что делает его намного лучше, чем мои другие усилия.
Сначала добавьте свойство в ваш пользовательский подкласс UITableViewController, чтобы отслеживать предыдущую ширину:
@property (nonatomic) CGFloat previousWidth;
Затем переопределите viewDidLayoutSubviews, чтобы проверить изменения ширины:
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
CGFloat width = self.view.frame.size.width;
if (self.previousWidth != width) {
self.previousWidth = width;
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
Это исправило проблемы с тем, что ячейкам моей таблицы иногда давали неправильную высоту.