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

222

Я использую пользовательский UITableViewCell, который имеет некоторые метки, кнопки и изображения для отображения. В ячейке есть одна метка, текст которой является NSStringобъектом, а длина строки может быть переменной. В связи с этим, я не могу установить высоту константы ячейки в UITableView«s heightForCellAtIndexметода. Высота ячейки зависит от высоты этикетки , которая может быть определена с помощью NSString«S 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)];
Vijayeta
источник

Ответы:

499

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

Objective-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«s sizeWithFont:constrainedToSize:lineBreakMode:метод для расчета высоты строки , а не просто выполнять какие - то глупые математику на indexPath :)

rpetrich
источник
1
Разве вы не имеете в виду [indexPath row] + 20?
fulvio
11
Фульвио: нет, цель состояла в том, чтобы сделать ряды явно разной высоты.
rpetrich
5
Чтобы установить конкретную высоту (например, 44 пикселя): верните 44;
mpemburn
Можете ли вы предоставить несколько дополнительных деталей о том, как использовать этот sizeWithFont: constrainedToSize: lineBreakMode:? У меня есть textView в моей ячейке, и я хочу получить его высоту в heightForRowAtIndexPath: чтобы установить высоту строки, но я не знаю, как ее получить! Спасибо
rdurand
Если вы вернете «[index row] * (some-value)», то первая ячейка может не отображаться, поскольку первое возвращаемое значение равно нулю. Следовательно, лучше вычислить необходимую высоту ячейки и вернуть вычисленное значение здесь, чтобы сделать все ячейки видимыми
Винаяк Г.Х.
134

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

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

jokkedk
источник
5
Это прекрасно работает, когда все ряды имеют одинаковую высоту. Оригинальный плакат, однако, не имеет такой ситуации, поэтому сам по себе ответ не является неправильным, но не отвечает на первоначальный вопрос. ОДНАКО я считаю важным отметить, что установка rowHeight, скорее всего, дает лучшую производительность, чем переопределение heightForRowAtIndexPath, потому что такие вещи, как вычисление размеров полосы прокрутки, это O (1) вместо O (n) в этом случае.
Даниэль Альбушат
2
Также обратите внимание (по очевидным причинам), что если tableView.rowHeightустановлено, heightForRowAtIndexPathне будет вызываться, если вы пытаетесь выяснить, почему (как я).
devios1
25

в пользовательском UITableViewCell -controller добавить это

-(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 -контроллере добавьте это

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 1.5; // your dynamic height...
}
hfossli
источник
CGRect newCellSubViewsFrame = self.bounds; CGRect newCellViewFrame = self.frame;
Pizzaiola Gorgonzola
17
#define FONT_SIZE 14.0f
#define CELL_CONTENT_WIDTH 300.0f
#define CELL_CONTENT_MARGIN 10.0f

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath      *)indexPath;
{
   /// Here you can set also height according to your section and row
   if(indexPath.section==0 && indexPath.row==0)
   {
     text=@"pass here your dynamic data";

     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;
   }
}

- (UITableViewCell *)tableView:(UITableView *)tv cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;
    UILabel *label = nil;

    cell = [tv dequeueReusableCellWithIdentifier:@"Cell"];
    if (cell == nil)
    {
       cell = [[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:@"Cell"];
    }
    ********Here you can set also height according to your section and row*********
    if(indexPath.section==0 && indexPath.row==0)
    {
        label = [[UILabel alloc] initWithFrame:CGRectZero];
        [label setLineBreakMode:UILineBreakModeWordWrap];
        [label setMinimumFontSize:FONT_SIZE];
        [label setNumberOfLines:0];
        label.backgroundColor=[UIColor clearColor];
        [label setFont:[UIFont systemFontOfSize:FONT_SIZE]];
        [label setTag:1];

        // NSString *text1 =[NSString stringWithFormat:@"%@",text];

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

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

        if (!label)
        label = (UILabel*)[cell viewWithTag:1];


        label.text=[NSString stringWithFormat:@"%@",text];
        [label setFrame:CGRectMake(CELL_CONTENT_MARGIN, CELL_CONTENT_MARGIN, CELL_CONTENT_WIDTH          - (CELL_CONTENT_MARGIN * 2), MAX(size.height, 44.0f))];
        [cell.contentView addSubview:label];
    }
return cell;
}
ravinder521986
источник
8
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    CGSize constraintSize = {245.0, 20000}
    CGSize neededSize = [ yourText sizeWithFont:[UIfont systemFontOfSize:14.0f] constrainedToSize:constraintSize  lineBreakMode:UILineBreakModeCharacterWrap]
if ( neededSize.height <= 18) 

   return 45
else return neededSize.height + 45 
//18 is the size of your text with the requested font (systemFontOfSize 14). if you change fonts you have a different number to use  
// 45 is what is required to have a nice cell as the neededSize.height is the "text"'s height only
//not the cell.

}
Алиса
источник
8

Я видел много решений, но все было неправильно или не завершено. Вы можете решить все проблемы с 5 строками в viewDidLoad и autolayout. Это для объективного 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) и нижний ярлык (ограничьте) понизьте "Приоритет удержания контента - по вертикали до 250"

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

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

Хосе Позе S
источник
1
Через 2 дня я добавлю больше изображений в одну и ту же ячейку с символами ImageView, а в другие subtableview этот метод работает всегда. Спасибо за +1 действительно.
Хосе Позе S
Замечательно!! Это поможет и другим. Спасибо :)
Джагдиш
Итак, как и было обещано, у вас есть новый код и новое изображение.
Хосе Позе S
Большое спасибо ... так держать ...- :)
Джагдиш
Это решение не работает, если вы создаете UITableViewCell программно, например, не используете Interface Builder
MB_iOSDeveloper
6

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

  • Назначить и реализовать источник данных tableview и делегировать
  • Присвоить UITableViewAutomaticDimensionrowHeight & оценка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 (& режим разрыва строки = обрезать хвост)
  • Установите все ограничения (сверху, снизу, справа налево) относительно его контейнера superview / cell.
  • Необязательно : Установите минимальную высоту для метки, если вы хотите, чтобы минимальная вертикальная область была покрыта меткой, даже если данных нет.

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

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

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

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

Krunal
источник
5

Благодаря всем сообщениям на эту тему, есть несколько действительно полезных способов отрегулировать 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;
} 
whyoz
источник
При анализе в XCode строка "int cellHeight;" создал логическую ошибку «Не определено или значение мусора возвращено вызывающей стороне». Установив cellHeight в 0, это исправило ошибку. Эта ошибка также появится, если вы не установите NSString равным nil внутри инструкции switch, аналогичной инструкции if / else if выше.
Whyoz
3

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

#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;
}
Самир Джварчан
источник
@Tisho Ты проверил это, Tisho, брат, чтобы сделать голосование против. Протестируйте внимательно, работает братан !!!!
Самир Джварчан
1
Я не отрицал ваш ответ. Я только что улучшил форматирование.
Тишо