Установка пользовательской высоты UITableViewCells

Я использую настраиваемый UITableViewCell, в котором есть несколько меток, кнопок и изображений для отображения. В ячейке есть одна метка, текст которой представляет собой объект NSString, а длина строки может быть переменной. Из-за этого я не могу установить постоянную высоту ячейки в методе UITableView heightForCellAtIndex. Высота ячейки зависит от высоты метки, которую можно определить с помощью метода NSString sizeWithFont. Я пробовал использовать его, но похоже, что я где-то ошибаюсь. Как это исправить?

Вот код, используемый для инициализации ячейки.

if (self = [super initWithFrame:frame reuseIdentifier:reuseIdentifier])
{
    self.selectionStyle = UITableViewCellSelectionStyleNone;
    UIImage *image = [UIImage imageNamed:@"dot.png"];
    imageView = [[UIImageView alloc] initWithImage:image];
    imageView.frame = CGRectMake(45.0,10.0,10,10);

    headingTxt = [[UILabel alloc] initWithFrame:   CGRectMake(60.0,0.0,150.0,post_hdg_ht)];
    [headingTxt setContentMode: UIViewContentModeCenter];
    headingTxt.text = postData.user_f_name;
    headingTxt.font = [UIFont boldSystemFontOfSize:13];
    headingTxt.textAlignment = UITextAlignmentLeft;
    headingTxt.textColor = [UIColor blackColor];

    dateTxt = [[UILabel alloc] initWithFrame:CGRectMake(55.0,23.0,150.0,post_date_ht)];
    dateTxt.text = postData.created_dtm;
    dateTxt.font = [UIFont italicSystemFontOfSize:11];
    dateTxt.textAlignment = UITextAlignmentLeft;
    dateTxt.textColor = [UIColor grayColor];

    NSString * text1 = postData.post_body;
    NSLog(@"text length = %d",[text1 length]);
    CGRect bounds = [UIScreen mainScreen].bounds;
    CGFloat tableViewWidth;
    CGFloat width = 0;
    tableViewWidth = bounds.size.width/2;
    width = tableViewWidth - 40; //fudge factor
    //CGSize textSize = {width, 20000.0f}; //width and height of text area
    CGSize textSize = {245.0, 20000.0f}; //width and height of text area
    CGSize size1 = [text1 sizeWithFont:[UIFont systemFontOfSize:11.0f]
                        constrainedToSize:textSize lineBreakMode:UILineBreakModeWordWrap];

    CGFloat ht = MAX(size1.height, 28);
    textView = [[UILabel alloc] initWithFrame:CGRectMake(55.0,42.0,245.0,ht)];
    textView.text = postData.post_body;
    textView.font = [UIFont systemFontOfSize:11];
    textView.textAlignment = UITextAlignmentLeft;
    textView.textColor = [UIColor blackColor];
    textView.lineBreakMode = UILineBreakModeWordWrap;
    textView.numberOfLines = 3;
    textView.autoresizesSubviews = YES;

    [self.contentView addSubview:imageView];
    [self.contentView addSubview:textView];
    [self.contentView addSubview:webView];
    [self.contentView addSubview:dateTxt];
    [self.contentView addSubview:headingTxt];
    [self.contentView sizeToFit];

    [imageView release];
    [textView release];
    [webView release];
    [dateTxt release];
    [headingTxt release];
}

Это метка, высота и ширина которой неправильны:

textView = [[UILabel alloc] initWithFrame:CGRectMake(55.0,42.0,245.0,ht)];

person Vijayeta    schedule 30.01.2009    source источник


Ответы (7)


Ваш UITableViewDelegate должен реализовать tableView:heightForRowAtIndexPath:

Цель-C

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 20;
}

Swift 5

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return indexPath.row * 20
}

Вы, вероятно, захотите использовать метод NSString sizeWithFont:constrainedToSize:lineBreakMode: для вычисления высоты вашей строки, а не просто выполнять какую-то глупую математику в indexPath :)

person rpetrich    schedule 30.01.2009
comment
Разве вы не имеете в виду [indexPath row] + 20? - person fulvio; 22.11.2010
comment
Фульвио: Нет, дело было в том, чтобы строки были явно разной высоты. - person rpetrich; 23.11.2010
comment
Чтобы установить определенную высоту (например, 44 пикселя): return 44; - person mpemburn; 16.05.2012
comment
Не могли бы вы подробнее рассказать о том, как использовать этот sizeWithFont: constrainedToSize: lineBreakMode:? У меня есть textView в моей ячейке, и я хочу получить его высоту в heightForRowAtIndexPath: чтобы установить высоту строки, но я не знаю, как ее получить! Спасибо - person rdurand; 24.07.2012
comment
Если вы вернете [index row] * (some-value), то первая ячейка может быть не видна, поскольку первое возвращаемое ею значение равно нулю. Следовательно, лучше рассчитать необходимую высоту ячейки и вернуть это вычисленное значение здесь, чтобы сделать все ячейки видимыми. - person Vinayak GH; 11.01.2016

Если все ваши строки имеют одинаковую высоту, просто установите свойство rowHeight UITableView, а не реализуйте heightForRowAtIndexPath. Документы Apple:

Использование tableView: heightForRowAtIndexPath: вместо rowHeight снижает производительность. Каждый раз, когда отображается табличное представление, он вызывает tableView: heightForRowAtIndexPath: в делегате для каждой из его строк, что может привести к значительной проблеме производительности с табличными представлениями, имеющими большое количество строк (примерно 1000 или более).

person jokkedk    schedule 18.01.2011
comment
Это отлично работает, когда все строки имеют одинаковую высоту. Однако на оригинальном плакате такой ситуации нет, поэтому сам по себе ответ не является неправильным, но не отвечает на исходный вопрос. ОДНАКО я считаю важным отметить, что установка rowHeight, скорее всего, дает лучшую производительность, чем переопределение heightForRowAtIndexPath, потому что такие вещи, как вычисление размеров полосы прокрутки, равны O (1 ) вместо O (n) в этом случае. - person Daniel Albuschat; 12.09.2012
comment
Также обратите внимание (по очевидным причинам), что если установлено tableView.rowHeight, heightForRowAtIndexPath не будет вызываться, если вы пытаетесь выяснить, почему (как и я). - person devios1; 19.04.2013

в настраиваемом контроллере UITableViewCell добавьте это

-(void)layoutSubviews {  

    CGRect newCellSubViewsFrame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    CGRect newCellViewFrame = CGRectMake(self.frame.origin.x, self.frame.origin.y, self.frame.size.width, self.frame.size.height);

    self.contentView.frame = self.contentView.bounds = self.backgroundView.frame = self.accessoryView.frame = newCellSubViewsFrame;
    self.frame = newCellViewFrame;

    [super layoutSubviews];
}

В UITableView -controller добавьте это

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 1.5; // your dynamic height...
}
person hfossli    schedule 19.01.2010
comment
CGRect newCellSubViewsFrame = self.bounds; CGRect newCellViewFrame = self.frame; - person Pizzaiola Gorgonzola; 30.04.2013

Я видел много решений, но все были неправильными или неполными. Вы можете решить все проблемы с помощью 5 строк в viewDidLoad и автозаполнении. Это для объекта C:

_tableView.delegate = self;
_tableView.dataSource = self;
self.tableView.estimatedRowHeight = 80;//the estimatedRowHeight but if is more this autoincremented with autolayout
self.tableView.rowHeight = UITableViewAutomaticDimension;
[self.tableView setNeedsLayout];
[self.tableView layoutIfNeeded];
self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0) ;

Для Swift 2.0:

 self.tableView.estimatedRowHeight = 80
 self.tableView.rowHeight = UITableViewAutomaticDimension      
 self.tableView.setNeedsLayout()
 self.tableView.layoutIfNeeded()
 self.tableView.contentInset = UIEdgeInsetsMake(20, 0, 0, 0)

Теперь создайте свою ячейку с помощью xib или в виде таблицы в раскадровке. При этом вам не нужно ничего больше реализовывать или переопределять. (Не забудьте число строк 0) и нижнюю метку (ограничение) понизить "Приоритет Content Hugging - Вертикальный до 250"

введите здесь описание изображения  введите описание изображения здесь

Вы можете загрузить код по следующему URL-адресу: https://github.com/jposes22/exampleTableCellCustomHeight

person Jose Pose S    schedule 26.01.2016
comment
Через 2 дня я помещу больше изображений с той же ячейкой с символами ImageView и другими подтаблицами, этот метод работает всегда. Спасибо за +1 на самом деле. - person Jose Pose S; 03.02.2016
comment
Замечательно!! Это поможет и другим. Спасибо :) - person Jagdish; 04.02.2016
comment
Итак, как и было обещано, у вас есть новый код и новое изображение. - person Jose Pose S; 07.02.2016
comment
Большое спасибо ... так держать ...- :) - person Jagdish; 08.02.2016
comment
Это решение не работает, если вы создаете UITableViewCell программно, например. не используя Interface Builder - person MB_iOSDeveloper; 13.03.2016
comment
Это решение не работает без ограничений и приоритета. Если вы хотите строить программно, вы должны также программно установить ограничения и изменить приоритет. Я могу загрузить пример, если хотите. - person Jose Pose S; 13.03.2016
comment
@SimonMoshenko да, это решение работает с асинхронными обновлениями данных, но, возможно, вам нужно перезагрузить данные, если вы измените весь текст и данные, если вы используете MVC, используйте делегат из ячейки для вызова контроллера и перезагрузки данных, если вы используете MVVM, у вас нет проблем, потому что ваше представление может перезагружать данные, когда они поступают. С другой стороны, я использую этот код с SDWebImage, и мне не нужно перезагружать данные. - person Jose Pose S; 16.06.2017

Чтобы установить автоматическое измерение для высоты строки и предполагаемой высоты строки, убедитесь, что следующие шаги, чтобы сделать автоматический размер эффективным для макета высоты ячейки / строки.

  • Назначьте и реализуйте источник данных tableview и делегируйте
  • Присвойте UITableViewAutomaticDimension rowHeight и приблизительноRowHeight
  • Реализуйте методы делегата / источника данных (т.е. heightForRowAt и верните ему значение UITableViewAutomaticDimension)

-

Цель C:

// in ViewController.h
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>

  @property IBOutlet UITableView * table;

@end

// in ViewController.m

- (void)viewDidLoad {
    [super viewDidLoad];
    self.table.dataSource = self;
    self.table.delegate = self;

    self.table.rowHeight = UITableViewAutomaticDimension;
    self.table.estimatedRowHeight = UITableViewAutomaticDimension;
}

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

    return UITableViewAutomaticDimension;
}

Swift:

@IBOutlet weak var table: UITableView!

override func viewDidLoad() {
    super.viewDidLoad()

    // Don't forget to set dataSource and delegate for table
    table.dataSource = self
    table.delegate = self

    // Set automatic dimensions for row height
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension
}



// UITableViewAutomaticDimension calculates height of label contents/text
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

Для экземпляра метки в UITableviewCell

  • Установить количество строк = 0 (& режим разрыва строки = обрезать хвост)
  • Установите все ограничения (сверху, снизу, справа налево) относительно контейнера супервизора / ячейки.
  • Необязательно: установите минимальную высоту для метки, если вы хотите, чтобы минимальная вертикальная область была покрыта меткой, даже если нет данных.

введите описание изображения здесь

Примечание. Если у вас более одной метки (UIElements) с динамической длиной, которая должна быть скорректирована в соответствии с размером содержимого: настройте «Приоритет сопротивления сжатию и объему контента» для меток, которые вы хотите расширить. / compress с более высоким приоритетом.

Здесь, в этом примере, я установил низкий приоритет сжатия и высокий приоритет сопротивления сжатию, что приводит к установке большего приоритета / важности для содержимого второй (желтой) метки.

введите описание изображения здесь

person Krunal    schedule 02.02.2018

Благодаря всем сообщениям по этой теме есть несколько действительно полезных способов настроить rowHeight UITableViewCell.

Вот подборка некоторых концепций от всех остальных, которые действительно помогают при сборке для iPhone и iPad. Вы также можете получить доступ к различным разделам и настроить их в соответствии с различными размерами представлений.

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

if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    int cellHeight = 0;

    if ([indexPath section] == 0) 
    {
        cellHeight = 16;
        settingsTable.rowHeight = cellHeight;
    }
    else if ([indexPath section] == 1)
    {
        cellHeight = 20;
        settingsTable.rowHeight = cellHeight;
    }

    return cellHeight;
}
else
{
    int cellHeight = 0;

    if ([indexPath section] == 0) 
    {
        cellHeight = 24;
        settingsTable.rowHeight = cellHeight;
    }
    else if ([indexPath section] == 1)
    {
        cellHeight = 40;
        settingsTable.rowHeight = cellHeight;
    }

    return cellHeight;
}
return 0;
} 
person whyoz    schedule 22.03.2012
comment
При анализе в XCode строка int cellHeight; создала логическую ошибку, вызывающей стороне возвращено значение Undefined или мусор. Установив для cellHeight значение 0, это исправило ошибку. Эта ошибка также появится, если вы не установите для NSString значение nil внутри оператора switch, аналогичного оператору if / else if выше. - person whyoz; 08.06.2012

Чтобы иметь динамическую высоту ячейки по мере увеличения текста метки, вам сначала нужно вычислить высоту, которую текст будет использовать в методе делегата -heightForRowAtIndexPath, и вернуть его с добавленными высотами других меток, изображений (максимальная высота текста + высота других статические компоненты) и используйте ту же высоту при создании ячеек.

#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 300.0f  
#define CELL_CONTENT_MARGIN 10.0f

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

    if (indexPath.row == 2) {  // the cell you want to be dynamic

        NSString *text = dynamic text for your label;

        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);
        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        CGFloat height = MAX(size.height, 44.0f);

        return height + (CELL_CONTENT_MARGIN * 2);
    }
    else {
        return 44; // return normal cell height
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UILabel *label;

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellIdentifier] ;
    }

    label = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, 280, 34)];

    [label setNumberOfLines:2];

    label.backgroundColor = [UIColor clearColor];

    [label setFont:[UIFont systemFontOfSize:FONT_SIZE]];

    label.adjustsFontSizeToFitWidth = NO;

    [[cell contentView] addSubview:label];


    NSString *text = dynamic text fro your label;

    [label setText:text];

    if (indexPath.row == 2) {// the cell which needs to be dynamic 

        [label setNumberOfLines:0];

        CGSize constraint = CGSizeMake(CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), 20000.0f);

        CGSize size = [text sizeWithFont:[UIFont systemFontOfSize:FONT_SIZE] constrainedToSize:constraint lineBreakMode:UILineBreakModeWordWrap];

        [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];

    }
    return  cell;
}
person Samir Jwarchan    schedule 01.08.2012
comment
@Tisho Вы проверили это, Tisho bro, чтобы проголосовать против. Тщательно протестируйте, работает братан !!!! - person Samir Jwarchan; 09.09.2012
comment
Я не отклонил ваш ответ. Я только что улучшил форматирование. - person Tisho; 09.09.2012