Лучший способ вычислить высоту UITableViewCell без фрейма contentView

РЕЗЮМЕ

Учитывая, что мы не всегда знаем, что такое кадр ячейки или ее содержимое будет (из-за редактирования, поворота, дополнительных представлений и т. д.), как лучше всего рассчитать высоту в tableView:heightForRowAtIndexPath:, когда ячейка содержит текстовое поле или метку переменной высоты?

Один из моих UITableViewControllerсодержит следующую презентацию: UITableViewCell с UITextView.

UITextView должен иметь ту же ширину и высоту, что и UITableViewCell.

enter image description here

Я создал подкласс 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. И я не могу получить это программно.

Эта ширина может быть одной из следующих:

  1. Обычная таблица iPhone, книжная ориентация
  2. Обычная таблица iPhone, альбомная ориентация
  3. Сгруппированная таблица iPhone, книжная ориентация
  4. Сгруппированная таблица iPhone, альбомная ориентация
  5. и то же самое для iPad (еще 4 значения)

И не забывайте, что рамка 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? ;)

Спасибо

9
задан Ajumal 27 April 2015 в 09:03
поделиться