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

В чем разница между всеми этими методами обновления макета? Все ли нужно?

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

[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];

И это из этого блока кода для высоты ячейки:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{

    RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    [cell updateFonts];

    NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
    cell.titleLabel.text =  [dataSourceItem valueForKey:@"title"];
    cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];

    cell.bodyLabel.preferredMaxLayoutWidth = tableView.bounds.size.width - (kLabelHorizontalInsets * 2.0f);

    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];
    [cell.contentView setNeedsLayout];
    [cell.contentView layoutIfNeeded];

    CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;

    return height;
}

Но что они делают по-другому? Почему все они нужны?

4b9b3361

Ответ 1

Layout

Предположим, вы инкапсулируете свою логику вида в подкласс UIView и называете ее SomeView. Это означает, что SomeView должен знать, как сама компоновка, то есть, как размещать в ней некоторые другие представления (вы также можете создать представление, которое рисуется без использования каких-либо подзаголовков, но это выходит за рамки потребностей среднего разработчика).

Этот макет выполняется [SomeView layoutSubviews]. У вас есть возможность переопределить его:

subview.frame = CGRectMake(100 + shiftX, 50 + shiftY, 250 + shiftX - paddingRight, ...
// Oh no, I think I didn't do it right.

но вам редко приходится это делать. В темные времена Cocoa Touch этот макет был широко распространен, но теперь я бы сказал, что 99% макетов можно покрыть с помощью автоматической компоновки.

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

Поэтому система часто вызывает [view layoutIfNeeded]. Вы также можете вызвать его в любое время, но это будет действовать только в том случае, если есть какое-то событие, которое вызвало [view setNeedsLayout], или если вы вызвали его вручную, как в этом случае.

Ограничения

Автоматическая компоновка (капитализированная таким образом в документация) называется так, потому что вы уходите [SomeView layoutSubviews], поскольку он унаследован от UIView и вместо этого укажите положение ваших подзонов в терминах ограничений.

При использовании автоматического макета система будет выполнять вызовы [view updateConstraintsIfNeeded] на каждом макете. Однако, только если установлен флаг [view setNeedsUpdateConstraints];, метод вызывает -updateConstraints (который выполняет реальную работу).

Если вы не используете автоматический макет, эти методы не имеют отношения.

Вы можете реализовать его как в этом примере.

Ваш пример

Редко бывает необходимо напрямую вызвать -layoutIfNeeded и -updateConstraintsIfNeeded, потому что движок UI будет делать это автоматически при каждом проходе макета. Однако в этом случае автор решил называть их немедленно; это потому, что результирующая высота нужна прямо сейчас, а не в какой-то момент в будущем.

Этот метод обновления высоты ячейки кажется правильным. Обратите внимание, что cell может быть вновь созданной ячейкой и, таким образом, не добавлен в иерархию представлений; это не влияет на его способность компоновки.

Заключение

В вашем пользовательском представлении перейдите со следующими параметрами, начиная с самого "универсального" и заканчивая большинством "настраиваемых":

  • Создание ограничений при создании вида (вручную или в IB)
  • Если вам нужно позже изменить ограничения, переопределите -updateConstraints.
  • Если у вас сложный макет, который не может быть описан выше, переопределите -layoutSubviews.

В коде, который изменяет то, что может изменить ваши ограничения, вызовите

[view setNeedsUpdateConstraints];

Если вам нужны результаты сразу, вызовите также

[view updateConstraintsIfNeeded]; 

Если в кадре изменения кода используется

[view setNeedsLayout]; 

и, наконец, если вы хотите получить результаты сразу, вызовите

[view layoutIfNeeded];

Вот почему все четыре вызова необходимы в этом случае.

Дополнительные материалы

Взгляните на подробное объяснение в статье Расширенные средства автоматической компоновки, objc.io issue # 3