Автоматическое определение размера UITableViewCell в iOS 8
У меня есть подкласс UITableViewCell, который содержит многострочную метку, и я хотел бы, чтобы ячейка динамически определяла динамику на основе содержимого этой метки. Я знаю, что iOS 8 вводил автоматическую калибровку ячеек на основе ограничений AutoLayout, и я нашел несколько примеров этого уже в SO, но у меня все еще есть некоторые проблемы с реализацией этого поведения.
Здесь моя реализация updateConstraints:
- (void)updateConstraints {
[super updateConstraints];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[_nameLabel(==20)]-10-[_tweetLabel]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_nameLabel, _tweetLabel)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_avatarView]-10-[_nameLabel]-10-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_avatarView, _nameLabel)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_nameLabel]-10-[_tweetLabel]-10-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_nameLabel, _tweetLabel)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:[_avatarView]-10-[_tweetLabel]-10-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_avatarView, _tweetLabel)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-10-[_avatarView(==45)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_avatarView)]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-10-[_avatarView(==45)]" options:0 metrics:nil views:NSDictionaryOfVariableBindings(_avatarView)]];
}
В контроллере табличного представления я установил высоту строки в UITableViewAutomaticDimension (и я также установил примерную высоту строки). Во время выполнения я получаю серию ошибок автоматического макета, и все ячейки представления таблиц кажутся почти полностью перекрывающимися.
Контексты автоматического компоновки заключаются между следующими ограничениями:
-
V:|-(10)-[_nameLabel]
-
V:[_nameLabel(20)]
-
V:[_nameLabel]-(10)-[_tweetLabel]
-
V:[_tweetLabel]-(10)-|
-
V:[cell(44)]
Я подозреваю, что последнее ограничение "UIView-Encapsulated-Layout-Height", которое заставляет высоту 44, является причиной проблемы, но я не совсем уверен, откуда это происходит, поэтому, надеюсь, кто-то может пролить некоторый свет в этом вопросе.
Ответы
Ответ 1
Чтобы реализовать автоматическую высоту строк для ячеек таблицы, вам необходимо сделать следующее:
-
Внедрение ограничений автоматического макета внутри содержимого cellView, которые позволяют представлению выражать свою предпочтительную высоту. Обязательно установите UILabel
на перенос слов на несколько строк.
Убедитесь, что вы определили осевую цепочку ограничений в обоих измерениях, то есть ограничения, которые в совокупности связывают весь путь от одного края представления к другому. Возможно, самый простой способ убедиться, что эти ограничения верны, - это реализовать свой пользовательский контент как простой старый UIView
(который легко проверить), а затем использовать ограничения, чтобы UITableViewCell.contentView
обнимал это представление. (Я использую этот смысл, чтобы автоматизировать создание "ячейки для просмотра".)
-
Установить tableView.rowHeight = UITableViewAutomaticDimension
- Установите
tableView.estimatedRowHeight = 400
или какое-либо другое достаточно щедрое значение, чтобы обход некоторых ошибок UIKit, когда оценка слишком низкая.
Я потратил некоторое время на работу с этой функцией. Это github repo показывает семь полных примеров ячеек отображения размера для самостоятельной калибровки, содержащих одну метку оберточного текста - программную, основанную на основах, раскадровки и т.д.
Наконец, не беспокойтесь слишком много, если вы видите предупреждения о неудовлетворительных ограничениях, упоминающих "UIView-Encapsulated-Layout-Height" или аналогичные при первом загрузке табличного представления. Это артефакт начального процесса UITableView
для создания ячейки, определения того, какой его размер должен быть основан на автоматических ограничениях компоновки, и сохранение UITableViewCell
плотной упаковки его contentView
. В репо, о котором я упоминал выше, содержится более подробное обсуждение и код для изучения этого довольно неудобного угла API.
Вы должны только беспокоиться о предупреждениях о нарушении ограничений, если они сохраняются даже после того, как ячейка загрузилась и прокручивается немного, или если вы видите неправильные макеты на начальном этапе. В этом случае, опять же, первым шагом всегда должно быть обеспечение того, чтобы ваши ограничения были правильными, развивая их и тестируя их изолированно, если это возможно, в простой UIView
.
Ответ 2
Я только что наткнулся на эту проблему.
Из многих других сообщений Stackoverflow они рекомендуют:
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
Это не сработало для меня сначала. Я обнаружил, что мне также нужно делать:
self.frame = CGRectMake(0, 0, self.frame.size.width, 50);
Мой пользовательский метод инициализации ячейки выглядит так:
-(id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
Я поместил код в свой метод initViews:
-(void)initViews
{
...
// fixes an iOS 8 issue with UIViewEncapsulated height 44 bug
self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
self.frame = CGRectMake(0, 0, self.frame.size.width, 50);
}
Проблема исчезла, и моя камера тоже выглядит правильно.
Это работает для вас?
Ответ 3
Уверены ли вы, что -translatesAutoresizingMaskIntoConstraints установлены на NO в ячейке? Если вы этого не сделаете, система генерирует ограничения на основе маски авторазмера, которая была предыдущим способом создания макета в iOS, и ее следует отключать при использовании автоматического макета.