РЕЗЮМЕ
Учитывая, что мы не всегда знаем, что такое кадр ячейки или ее содержимое будет (из-за редактирования, поворота, дополнительных представлений и т. д.), как лучше всего рассчитать высоту в tableView:heightForRowAtIndexPath:
, когда ячейка содержит текстовое поле или метку переменной высоты?
Один из моих UITableViewController
содержит следующую презентацию:
UITableViewCell с UITextView.
UITextView должен иметь ту же ширину и высоту, что и UITableViewCell.
Я создал подкласс UITableViewCell, а затем инициализировал его с помощью UITextView (UITextView является закрытым полем моего UITableViewController)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = @"TextViewCell";
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[BTExpandableTextViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier textView:_notesTextView] autorelease];
}
return cell;
}
Я реализовал следующий метод в своем подклассе UITableViewCell:
- (void)layoutSubviews{
[super layoutSubviews];
CGFloat height = [textView.text sizeWithFont:textView.font constrainedToSize:CGSizeMake(textView.frame.size.width, MAXFLOAT)].height + textView.font.lineHeight;
textView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, (height < textView.font.lineHeight * 4) ? textView.font.lineHeight * 4 : height);
[self.contentView addSubview:textView];
}
и, конечно, я реализовал следующий UITableViewDataSource метод (смотрите! Я использую self.view.frame.size.ширина (но на самом деле мне нужна ширина кадра UITableViewCell contentView):
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{
CGFloat height = [_notesTextView.text sizeWithFont:_notesTextView.font
constrainedToSize:CGSizeMake(self.view.frame.size.width, MAXFLOAT)].height;
CGFloat groupedCellCap = 20.0;
height += groupedCellCap;
if(height < [BTExpandableTextViewCell minimumTextViewHeightWithFont:_notesTextView.font]){
height = [BTExpandableTextViewCell minimumTextViewHeightWithFont:_notesTextView.font];
}
return height;
}
также я реализовал следующий метод (это не так важно, но я все равно опубликую его, просто чтобы объяснить, что высота ячейки является динамической, она будет уменьшаться или расширяться после изменения текста в UITextView)
- (void)textViewDidChange:(UITextView *)textView{
CGFloat height = [_notesTextView.text sizeWithFont:_notesTextView.font
constrainedToSize:CGSizeMake(_notesTextView.frame.size.width, MAXFLOAT)].height;
if(height > _notesTextView.frame.size.height){
[self.tableView beginUpdates];
[self.tableView endUpdates];
}
}
А теперь мой вопрос: После загрузки представления UITableViewController вызывает методы в следующем порядке: (для упрощения я уберу некоторые, например, titleForHeaderInSection и т. д.)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath{
и только потом
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Смотри! Я должен вернуть правильную высоту UITableViewCell перед cellForRowAtIndexPath! Это означает: я не знаю кадр UITableViewCell contentView. И я не могу получить это программно.
Эта ширина может быть одной из следующих:
И не забывайте, что рамка contentView может быть меньше из-за аксессуара UITableViewCell или из-за состояния редактирования UITableView. (например, если у нас есть UITableViewCell с многострочным UILabel любой высоты в любом состоянии редактирования и с любым аксессуаром)
Таким образом, эта проблема является фундаментальной: я просто не могу получить ширину рамки ячейки contentView для ограничения, потому что я должен вернуть эту высоту перед макетами ячеек contentView. (Кстати, это довольно логично) Но этот фрейм contentView действительно имеет значение.
Конечно, иногда я могу точно знать эту ширину и "жестко запрограммировать" ее. (например: UITableViewCellAccessoryDisclosureIndicator имеет ширину 20 px, а tableView не может быть в состоянии редактирования, тогда я могу написать self.view.frame.size.width - 20 и задача выполнена)! Или иногда contentView равен фрейму просмотра UITableViewController!
Иногда я использую self.view.frame.width в методе -tableView:heightForRowAtIndexPath:.. (как сейчас, и он работает довольно хорошо, но не идеально из-за сгруппированного UITableView, должен вычесть некоторые постоянные значения, и они различаются для 2 устройств * 2 ориентаций)
Иногда у меня есть некоторые константы #defined в UITableViewCell (если я точно знаю ширину)...
Иногда я использую какой-то фиктивный предварительно распределенный UITableViewCell (что просто глупо , но иногда довольно элегантен и удобен в использовании)...
Но мне ничего из этого не нравится.
Какое решение лучше? Возможно, мне следует создать какой-нибудь вспомогательный класс, который будет инициализирован с такими параметрами: вспомогательные представления, ориентация устройства, тип устройства, состояние редактирования табличного представления, стиль табличного представления (обычный, сгруппированный), рамка представления контроллера и некоторые другие, которые будут включать некоторые константы (например, сгруппированное смещение tableView и т. д.) и использовать его для поиска ожидаемая ширина UITableViewCell contentView? ;)
Спасибо