Подтвердить что ты не робот

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, чтобы обнять его текстовый контент?

4b9b3361

Ответ 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];
    }
}

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