Как рассчитать heightForRowAtIndexPath, когда ячейка еще не построена? - PullRequest
5 голосов
/ 14 марта 2011

Вопрос - Как лучше всего рассчитать высоту строки в методе «heightForRowAtIndexPath» UITableViewController, учитывая, что:

  1. Я использую пользовательский подкласс UITableViewCell и фактический размерподпредставление (например, UILabels) рассчитывается во время выполнения и зависит от таких вещей, как, например, если пользователь изменил размер шрифта
  2. ячейки на самом деле не подготовлены, это кажется до "heightForRowAtIndexPath", поэтому вы не можетеположитесь на вызов вашей конкретной пользовательской ячейки, чтобы запросить ее

На данный момент я могу думать только о том, чтобы: 1. В вашем подклассе UITableViewCell создать метод, который вычисляет высоту каждого подпредставления (например, UILabel), который находится в подклассе UITableViewCell - затем используйте его в подклассе ячейки при создании экземпляров 2. Также в пользовательском подклассе создайте метод класса, который проходит через все UILabels, вызывая вышеупомянутый метод, чтобы подвести итогвысоты и, следовательно, отработать общую строку хейGHT.Это должно было бы получить данные, переданные ему (например, текст в каждой из UILabels). 3. В UITableViewController "heightForRowAtIndexPath" затем вы должны вызвать метод типа "calRowHeight" из (2) выше, передав ему текстовые данные метки,Поэтому эффективно вызывайте метод класса для своего пользовательского подкласса ячеек, который знает, как рассчитать общую высоту строки, но использует ту же логику, что и ячейка, которая тоже нужна ...

Есть ли более простой способ, чем этот?пропал?

Ответы [ 2 ]

14 голосов
/ 14 марта 2011

Когда создается UITableView, и всякий раз, когда вы отправляете ему сообщение reloadData, источнику данных отправляется одно сообщение heightForRowAtIndexPath для каждой ячейки.Поэтому, если в вашей таблице 30 ячеек, это сообщение отправляется 30 раз.

Скажем, на экране видны только шесть из этих 30 ячеек.В этом случае при создании и при отправке ему сообщения reloadData UITableView будет отправлять одно сообщение cellForRowAtIndexPath на видимую строку, то есть это сообщение отправляется шесть раз.

Почему Apple реализует его так?Частично причина в том, что почти всегда дешевле вычислить высоту строки, чем построить и заполнить целую ячейку.И учитывая, что во многих таблицах высота каждой ячейки будет одинаковой, она зачастую значительно дешевле.И отчасти причина в том, что iOS нужно знать размер всей таблицы: это позволяет ей создавать полосы прокрутки и настраивать их в представлении прокрутки и т. Д.

Если высота строк варьируется по размеру, потому чтоони содержат различное количество текста, вы можете использовать один из методов sizeWithFont: в соответствующей строке для выполнения вычислений.Это быстрее, чем создание представления и последующее измерение результата.Обратите внимание, что если вы измените высоту ячейки, вам нужно будет либо перезагрузить всю таблицу (с помощью reloadData - это будет запрашивать у делегата каждую высоту, но только запрашивать видимые ячейки) ИЛИ выборочно перезагружать строки, где размер имеетизменено.

Дополнительный материал Если я понимаю следующий вопрос в комментарии, может помочь следующее:

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

  • Убедитесь, что tableView: heightForRowAtIndexPath: метод знает, находитесь ли вы в режиме редактирования или нет.(Он может запросить tableView с помощью isEditing.) И затем получить метод, который возвращает правильную высоту, в зависимости от того, находитесь ли вы в режиме редактирования или нет.

  • В вашем setEditing: animated:Метод в UITableViewController (или UIViewController, в зависимости от того, что вы используете - есть некоторые различия в зависимости от того, что вы используете, поэтому стоит тщательно проверить документацию), отправив сообщение reloadData в tableView после изменения его состояния.Это заставит tableView захватывать высоты каждой строки, и он будет заново выбирать ячейки для видимых строк.TableView обрабатывает сужение ячеек при входе в режим редактирования, но если вы хотите больше работать с макетом, сделайте это в tableView: cellForRowAtIndex :.Как отмечалось выше, общая стратегия состоит в том, чтобы найти способ быстрого расчета высоты.С размером текстаWithFont: (и его варианты) может сделать это.Если у вас есть изображения и т. Д., То вы можете взять их размеры и сделать некоторые суммы.

  • В дополнение к этим шагам вы можете также захотеть немного прокрутить tableView после переключения режимов.Если высота ваших строк различна, то после переключения вы окажетесь в неверной позиции в таблице.Подход, который я здесь выбрал, заключается в использовании executeSelector: withObject: afterDelay после перезагрузки таблицы для вызова метода, который выполняет настройку прокрутки.Вам нужно использовать задержку, чтобы дать возможность tableView собрать новые высоты и новые ячейки таблицы.(Возможно, есть более разумный способ сделать это.) Я делаю некоторые суммы, чтобы выполнить настройку прокрутки на основе разницы между origin.y tableView: cellForRowAtIndexPath: первой видимой строки ячейки на экране до и после перезагрузки.Так, например, чтобы получить позицию до предварительной загрузки, что-то вроде этого.

    CGPoint offset = [[self tableView] contentOffset];
    NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:CGPointMake(0,offset.y)];
    CGFloat preCellOffset = [[[self tableView] cellForRowAtIndexPath:indexPath] origin].y;
    
3 голосов
/ 14 марта 2011

То, что я сделал в прошлом, что я не уверен, является наиболее эффективным, происходит из моего heightForRowAtIndexPath вызова метода cellForRowAtIndexPath, тогда я спрашиваю представление для этой ячейки ее высоту. Я сделал аналогичные вещи для высоты верхнего и нижнего колонтитула. Таким образом, если я изменяю ячейку, верхний или нижний колонтитул, мне не нужно забывать идти и обновлять соответствующий метод высоты.

...