Definindo a altura UITableViewCells personalizada

222

Estou usando um UITableViewCell personalizado que possui alguns rótulos, botões e visualizações de imagem a serem exibidos. Há um rótulo na célula cujo texto é um NSStringobjeto e o comprimento da string pode ser variável. Devido a isso, não posso definir uma altura constante para a célula no método UITableView's heightForCellAtIndex. A altura da célula depende da altura da etiqueta que pode ser determinado usando o NSString's sizeWithFontmétodo. Tentei usá-lo, mas parece que estou errado em algum lugar. Como pode ser consertado?

Aqui está o código usado para inicializar a célula.

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

Este é o rótulo cuja altura e largura estão incorretas:

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

Respostas:

499

Você UITableViewDelegatedeve implementartableView:heightForRowAtIndexPath:

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

Você provavelmente desejará usar NSStringo sizeWithFont:constrainedToSize:lineBreakMode:método de calcular a altura da linha, em vez de apenas executar algumas contas tolas no indexPath :)

rpetrich
fonte
1
Você não quis dizer [indexPath row] + 20?
Fulvio
11
Fulvio: não, o objetivo era fazer com que as linhas tivessem alturas obviamente diferentes.
rpetrich
5
Para definir uma altura específica (por exemplo, 44 ​​pixels): retorne 44;
mpemburn
Você pode fornecer mais alguns detalhes sobre como usar esse sizeWithFont: constrainedToSize: lineBreakMode:? Eu tenho um textView na minha célula e quero obter sua altura em heightForRowAtIndexPath: para definir a altura da linha, mas não sei como obtê-la! Graças
rdurand
Se você retornar "[linha do índice] * (algum valor)", a primeira célula poderá não estar visível, pois o primeiro valor retornado será zero. Daí a sua melhor você calcular a altura da célula necessária e retorno que valor calculado aqui para fazer todas as células visíveis
Vinayak GH
134

Se todas as suas linhas tiverem a mesma altura, basta definir a rowHeightpropriedade do UITableView em vez de implementar o heightForRowAtIndexPath. Documentos da Apple:

Há implicações de desempenho no uso de tableView: heightForRowAtIndexPath: em vez de rowHeight. Toda vez que uma exibição de tabela é exibida, ele chama tableView: heightForRowAtIndexPath: no delegado de cada uma de suas linhas, o que pode resultar em um problema de desempenho significativo com as exibições de tabela com um grande número de linhas (aproximadamente 1000 ou mais).

jokkedk
fonte
5
Isso funciona perfeitamente quando todas as linhas têm a mesma altura. O pôster original, no entanto, não possui essa situação; portanto, a resposta em si não é incorreta, mas não responde à pergunta original. No entanto , acho importante observar que a definição de rowHeight provavelmente produz um desempenho melhor do que a substituição de heightForRowAtIndexPath porque, como calcular as dimensões da barra de rolagem, é O (1) em vez de O (n) nesse caso.
Daniel Albuschat
2
Observe também (por razões óbvias) que, se tableView.rowHeightestiver definido, heightForRowAtIndexPathnão será chamado, caso você esteja tentando descobrir o porquê (como eu estava).
precisa saber é
25

em um controlador UITableViewCell personalizado, adicione este

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

No controlador UITableView, adicione este

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return [indexPath row] * 1.5; // your dynamic height...
}
hfossli
fonte
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
fonte
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.

}
Alice
fonte
8

Vi muitas soluções, mas tudo estava errado ou incompleto. Você pode resolver todos os problemas com 5 linhas no viewDidLoad e no autolayout. Isto para o objetivo 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) ;

Para o 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)

Agora crie seu celular com xib ou em tableview no Storyboard. Com isso, você não precisa implementar nada mais ou substituir. (Não esqueça o número de linhas 0) e o rótulo inferior (restrinja) faça o downgrade "Prioridade de aceitação de conteúdo - vertical para 250"

insira a descrição da imagem aqui insira a descrição da imagem aqui

Você pode fazer o download do código no próximo URL: https://github.com/jposes22/exampleTableCellCustomHeight

Jose Pose S
fonte
1
Em dois dias, colocarei mais imagens com a mesma célula com os caracteres ImageView e, em outras sub-visualizações, esse método funcionará sempre. Obrigado por +1 realmente.
José Pose S
Isso é ótimo!! Também ajudará os outros. Obrigado :)
jagdish
Então, como prometido, aqui você tem um novo código e uma nova imagem.
José Pose S
Muito obrigado ... mantê-lo ...- :)
jagdish
Esta solução não funciona se você está criando o UITableViewCell programaticamente por exemplo, não usando Interface Builder
MB_iOSDeveloper
6

Para definir a dimensão automática para a altura da linha e a altura estimada da linha, verifique as etapas a seguir, para que a dimensão automática seja eficaz no layout de altura da célula / linha.

  • Atribuir e implementar dados de visualização de tabela
  • Atribuir UITableViewAutomaticDimensiona rowHeight e estimadoRowHeight
  • Implemente métodos delegate / dataSource (isto é, heightForRowAte retorne um valor UITableViewAutomaticDimensiona ele)

-

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

Rápido:

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

Para instância de rótulo em UITableviewCell

  • Definir número de linhas = 0 (& modo de quebra de linha = cauda truncada)
  • Defina todas as restrições (superior, inferior, direita esquerda) em relação ao seu contêiner de superview / célula.
  • Opcional : Defina a altura mínima para a etiqueta, se desejar que a área vertical mínima seja coberta pela etiqueta, mesmo se não houver dados.

insira a descrição da imagem aqui

Nota : Se você tiver mais de um rótulo (UIElements) com comprimento dinâmico, o qual deverá ser ajustado de acordo com o tamanho do conteúdo: Ajuste 'Prioridade de resistência a compressão e compressão de conteúdo' para rótulos que você deseja expandir / compactar com prioridade mais alta.

Aqui neste exemplo, defino prioridade de baixa resistência ao aperto e alta resistência à compressão, o que leva a definir mais prioridade / importância para o conteúdo do segundo rótulo (amarelo).

insira a descrição da imagem aqui

Krunal
fonte
5

Graças a todas as postagens deste tópico, existem algumas maneiras realmente úteis de ajustar o rowHeight de um UITableViewCell.

Aqui está uma compilação de alguns dos conceitos de todos os outros que realmente ajudam na criação para o iPhone e iPad. Você também pode acessar diferentes seções e ajustá-las de acordo com os diferentes tamanhos de visualizações.

- (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
fonte
Ao analisar no XCode, a linha "int cellHeight;" criou um erro lógico, "Valor indefinido ou lixo retornado ao chamador". Ao definir cellHeight como 0, isso corrigiu o erro. Este erro também aparecerá se você não definir um NSString como nulo dentro de uma instrução switch semelhante à instrução if / else if acima.
whyoz
3

Para ter a altura dinâmica da célula à medida que o texto do Label aumenta, primeiro você precisa calcular a altura, que o texto usará no -heightForRowAtIndexPathmétodo delegado e retorná-lo com as alturas adicionadas de outras etiquetas, imagens (altura máxima do texto + altura de outras imagens estáticas componenets) e use a mesma altura na criação de células.

#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;
}
Samir Jwarchan
fonte
@Tisho Você já testou Tisho bro para fazer o voto negativo. Teste com cuidado, funciona mano !!!!
Samir Jwarchan
1
Eu não votei na sua resposta. Acabei de melhorar a formatação.
Tisho 9/09/12