Рекомендации по рисованию динамической высоты строки UITableView

Возможно, дубликат, но я не мог найти конкретный вопрос о SO, так что вот оно.

Мне интересно узнать динамически изменяющиеся высоты для всех строк, как правило, потому что вы не знаете длину NSString, которая использовалась для метки.

Я знаю, что вы должны использовать этот метод делегата для изменения высоты строки:

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

Проблема заключается в том, что этот метод делегата называется ПЕРЕД тем, как создается ячейка (т.е. вызывается до cellForRowAtIndexPath).

Итак, я думал о создании mock-ячейки в viewWillAppear и методе, который добавляет высоты ячеек в массив, который сопоставляется с источником данных таблицы (который в моем случае также является массивом).

viewWillAppear реализует этот важный метод для получения высоты:

[NSString sizeWithFont: constrainedToSize: lineBreakMode:]

Затем в heightForRowAtIndexPath я могу вернуть высоту ячейки так:

//cellHeights is an ivar populated in viewWillAppear
return [[cellHeights objectAtIndex:indexPath.row] floatValue];

Мне было интересно, есть ли лучший способ динамически изменять высоту строки?

Я понимаю, что это ухудшит производительность для большого количества строк (я полагаю, более 1000). Но в моем случае мои ряды никогда не приблизится к этому числу. Таким образом, удар производительности ничтожно мал.

Спасибо заранее!

Ответ 1

Отличный вопрос! Фактически, я сделал что-то подобное в некоторых моих приложениях.

Я могу вспомнить пару альтернатив, но все они по одной теме. Вы также можете просто использовать sizeWithFont: внутри heightForRowAtIndexPath: и покончить с массивом. В этом случае вы можете получить удар производительности для пересчета размера каждый раз, если эта операция стоит дорого.

Вы можете сделать "ленивую загрузку" массива cellHeights внутри heightForRowAtIndexPath:, чтобы он выглядел примерно так:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    if ([cellHeights objectAtIndex:indexPath.row] == nil) {
        ... calculate height and store it in the array at the correct index...
    }

    return [[cellHeights objectAtIndex:indexPath.row] floatValue];
}

Преимущество, о котором я сейчас думаю, заключается в том, что вы только вычислите высоты для ячеек, которые определенно будут загружены. Если вы выполните расчет в viewWillAppear, я думаю, вы в конечном итоге делаете это для каждой ячейки, независимо от того, отображается ли она?

Наконец, вы можете поместить размер в свою модель данных. Если это, например, массив строк, вы можете создать класс, который имеет два свойства: строку и свойство "представление". Затем вы можете пересчитать размер строки каждый раз при изменении значения строки. Тогда будет только один массив, а не два, который будет отображаться на ваш источник данных, заполненный классом данных, содержащим как строку, так и размер отображения строки, и значение будет вычисляться, когда строка изменяется, а вовсе не раз когда появится представление.

В любом случае, я хотел бы услышать некоторые комментарии по этим различным подходам.

Ответ 3

У меня тоже проблема в UITableView, когда я прокручиваю табличное представление (на iPhone 3gs). Я видел много лагов. Поэтому я открываю время профилировщик (очень хороший инструмент для оптимизации), и проблема заключалась в том, что я вызываю функцию sizeWithFont. Лучшим решением для решения этой проблемы является call sizeWithFont в конструкторе.