Встановлення власної висоти UITableViewCells


222

Я використовую користувальницький UITableViewCell, який має кілька міток, кнопок і зображень для відображення. У комірці є одна мітка, текст якої є NSStringоб’єктом, а довжина рядка може бути змінною. Через це я не можу встановити постійну висоту клітинки методом UITableView's heightForCellAtIndex. Висота комірки залежить від висоти мітки, яку можна визначити за допомогою методу NSStrings 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)];

Відповіді:


499

Ви UITableViewDelegateповинні реалізуватиtableView:heightForRowAtIndexPath:

Ціль-С

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

Швидкий 5

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

Ви, ймовірно , хочете використовувати NSString«s sizeWithFont:constrainedToSize:lineBreakMode:метод для розрахунку висоти рядка , а не просто виконувати будь - то дурні математику на indexPath :)


1
Ви не маєте на увазі [indexPath рядок] + 20?
фульвіо

11
Фульвіо: ні, справа полягала в тому, щоб рядки мали явно різну висоту.
rpetrich

5
Щоб встановити конкретну висоту (наприклад, 44 пікселі): поверніть 44;
1212

Чи можете ви надати ще кілька подробиць про те, як використовувати цей розмірWithFont: constrainedToSize: lineBreakMode:? У мене в комірці є textView, і я хочу отримати його висоту у висотуForRowAtIndexPath: щоб встановити висоту рядка, але я не знаю, як це отримати! Дякую
rdurand

Якщо ви повернете "[рядок індексу] * (деяке значення)", тоді перша комірка може бути не видно, оскільки перше значення, яке вона повертає, дорівнює нулю. Отже, краще обчислити потрібну висоту комірки і повернути тут обчислене значення, щоб зробити всі клітини видимими
Vinayak GH,

134

Якщо всі ваші рядки однакової висоти, просто встановіть rowHeightвластивість UITableView, а не реалізуйте heightForRowAtIndexPath. Документи Apple:

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


5
Це прекрасно працює, коли всі ряди мають однакову висоту. Однак у оригінальному плакаті такої ситуації немає, тому відповідь сама по собі є невірною, але не відповідає на оригінальне запитання. ЯКЩО мені важливо зазначити, що встановлення rowHeight, швидше за все, дає кращі показники, ніж перевищення висотиForRowAtIndexPath, оскільки такі речі, як обчислення розмірів смуги прокрутки, є O (1), а не O (n).
Даніель Альбусхат

2
Зауважте також (з очевидних причин), що якщо tableView.rowHeightце встановлено, heightForRowAtIndexPathне буде викликано, якщо ви намагаєтесь з'ясувати, чому (як я).
devios1

25

у користувацький контролер 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 додайте це

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 1.5; // your dynamic height...
}

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

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 та автоматичному розкладі. Це для об'єктивного 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) ;

Для швидкого 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 або за допомогою табличного перегляду на своїй дошці розкадрувань. З цим вам більше нічого не потрібно реалізовувати та не змінювати. (Не забудьте число os рядків 0) та нижню мітку (обмежуйте) пониження рівня "Вміст пріймається пріоритетом - по вертикалі до 250"

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

Ви можете завантажити код у наступній URL-адресі: https://github.com/jpose22/exampleTableCellCustomHeight


1
Через 2 дні я помістять більше зображень у ту саму клітинку з символами ImageView, а в іншому підрозділі цей метод працює завжди. Дякую за +1 дійсно
Jose Pose S

Це чудово!! Це допоможе і іншим. Дякую :)
jagdish

Отже, як і обіцяли, тут у вас новий код і нове зображення.
Jose Pose S

Велике спасибі ... продовжуйте це ...- :)
jagdish

Це рішення не працює, якщо ви створюєте UITableViewCell програмно, наприклад, не використовуючи програму Interface Builder
MB_iOSDeveloper

6

Щоб встановити автоматичний розмір для висоти рядка та передбачуваної висоти рядка, переконайтесь, що слід виконати наступні кроки, щоб автоматичний параметр був ефективним для компонування висоти комірки / рядка.

  • Призначення та реалізація dataview dataSource та делегат
  • Призначте UITableViewAutomaticDimensionдо рядкаВисота та Оцінка РоуВест
  • Реалізація методів delegate / dataSource (тобто 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;
}

Швидкий:

@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) з динамічною довжиною, яку слід відрегулювати відповідно до її розміру вмісту: Відрегулюйте "Пріоритет обійму вмісту та стійкість до стиснення" для міток, які потрібно розгорнути / стиснути з більшим пріоритетом.

Тут у цьому прикладі я встановлюю низький пріоритет обіймів та високий опір стисненню, що призводить до встановлення більшого пріоритету / важливості для вмісту другої (жовтої) мітки.

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


5

Завдяки всім повідомленням на цю тему, є кілька дійсно корисних способів відкоригувати rowHeight of 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;
} 

При аналізі в XCode рядок "int cellHeight;" створила логічну помилку: "Невизначене або сміттєве значення повертається до абонента". Встановивши cellHeight на 0, це виправило помилку. Ця помилка також з’явиться, якщо ви не встановите NSString на нуль всередині оператора перемикання, подібного до оператора if / else, якщо вище.
Whyoz

3

Щоб динамічна висота комірки зростала, коли текст мітки збільшується, спочатку потрібно обчислити висоту, яку текст використовуватиме в -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;
}

@Tisho Ви перевірили це брато Tisho, щоб проголосувати. Тестуйте уважно, це працює брато !!!!
Самір Юрчан

1
Я не відмовився від вашої відповіді. Я тільки вдосконалив форматування.
Тишо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.