Définition de la hauteur UITableViewCells personnalisée

222

J'utilise un UITableViewCell personnalisé qui a des étiquettes, des boutons et des vues d'image à afficher. Il existe une étiquette dans la cellule dont le texte est un NSStringobjet et la longueur de la chaîne peut être variable. En raison de cela, je ne peux pas définir une hauteur constante à la cellule dans la UITableViewde heightForCellAtIndexméthode. La hauteur dépend de la hauteur de l'étiquette de la cellule qui peut être déterminée en utilisant la NSStringde » sizeWithFontméthode. J'ai essayé de l'utiliser, mais il semble que je me trompe quelque part. Comment peut-il être corrigé?

Voici le code utilisé pour initialiser la cellule.

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

C'est l'étiquette dont la hauteur et la largeur ne vont pas:

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

Réponses:

499

Vous devez UITableViewDelegatemettre en œuvretableView:heightForRowAtIndexPath:

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

Vous voudrez probablement utiliser NSStringla sizeWithFont:constrainedToSize:lineBreakMode:méthode de pour calculer la hauteur de votre ligne plutôt que de simplement effectuer des calculs stupides sur l'indexPath :)

rpetrich
la source
1
Ne voulez-vous pas dire [indexPath row] + 20?
fulvio
11
Fulvio: non, le but était de faire en sorte que les rangées aient évidemment des hauteurs différentes.
rpetrich
5
Pour définir une hauteur spécifique (par exemple, 44 pixels): retournez 44;
mpemburn
Pouvez-vous fournir quelques détails supplémentaires sur la façon d'utiliser cette tailleWithFont: constrainedToSize: lineBreakMode:? J'ai un textView dans ma cellule, et je veux obtenir sa hauteur dans heightForRowAtIndexPath: afin de définir la hauteur de la ligne, mais je ne sais pas comment l'obtenir! Merci
rdurand
Si vous renvoyez "[ligne d'index] * (une certaine valeur)", la première cellule peut ne pas être visible car la première valeur qu'elle renvoie est zéro. Par conséquent, il est préférable de calculer la hauteur de cellule nécessaire et de renvoyer cette valeur calculée ici pour rendre toutes les cellules visibles
Vinayak GH
134

Si toutes vos lignes ont la même hauteur, définissez simplement la rowHeightpropriété de UITableView plutôt que d'implémenter heightForRowAtIndexPath. Documents Apple:

L'utilisation de tableView: heightForRowAtIndexPath: au lieu de rowHeight a des implications sur les performances. Chaque fois qu'une vue de table est affichée, elle appelle tableView: heightForRowAtIndexPath: sur le délégué pour chacune de ses lignes, ce qui peut entraîner un problème de performances significatif avec les vues de table ayant un grand nombre de lignes (environ 1000 ou plus).

jokkedk
la source
5
Cela fonctionne parfaitement bien lorsque toutes les lignes ont la même hauteur. L'affiche originale, cependant, n'a pas cette situation, donc la réponse en soi n'est pas incorrecte, mais ne répond pas à la question d'origine. TOUTEFOIS, je trouve important de noter que la définition de rowHeight donne probablement de meilleures performances que le remplacement de heightForRowAtIndexPath, car des choses comme le calcul des dimensions de la barre de défilement est O (1) au lieu de O (n) dans ce cas.
Daniel Albuschat
2
Notez également (pour des raisons évidentes) que si tableView.rowHeightest défini, heightForRowAtIndexPathne sera pas appelé, au cas où vous essayez de comprendre pourquoi (comme je l'étais).
devios1
25

dans un contrôleur UITableViewCell personnalisé, ajoutez ceci

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

Dans le contrôleur UITableView, ajoutez ceci

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

J'ai vu beaucoup de solutions mais tout était faux ou incomplet. Vous pouvez résoudre tous les problèmes avec 5 lignes dans viewDidLoad et autolayout. Ceci pour l'objectif 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) ;

Pour 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)

Maintenant, créez votre cellule avec xib ou dans tableview dans votre Storyboard Avec cela, vous n'avez plus besoin de rien implémenter ou de remplacer. (N'oubliez pas le numéro des lignes 0) et le libellé inférieur (contraindre) rétrograder "Content Hugging Priority - Vertical to 250"

entrez la description de l'image ici entrez la description de l'image ici

Vous pouvez télécharger le code dans l'url suivante: https://github.com/jposes22/exampleTableCellCustomHeight

Jose Pose S
la source
1
Dans 2 jours, je mettrai plus d'images avec la même cellule avec les caractères ImageView, et d'autres subtableview cette méthode fonctionne toujours. Merci pour +1 vraiment.
Jose Pose S
C'est génial!! Cela aidera également les autres. Merci :)
jagdish
Donc, comme promis, vous avez ici un nouveau code et une nouvelle image.
Jose Pose S
Merci beaucoup ... continuez comme ça ...- :)
jagdish
Cette solution ne fonctionne pas si vous créez UITableViewCell par programme, par exemple en n'utilisant pas Interface Builder
MB_iOSDeveloper
6

Pour définir la dimension automatique pour la hauteur de ligne et la hauteur de ligne estimée, assurez-vous que les étapes suivantes sont effectives, la dimension automatique est efficace pour la disposition de hauteur de cellule / ligne.

  • Attribuer et implémenter dataSource tableview et déléguer
  • Attribuer UITableViewAutomaticDimensionà rowHeight et estimeRowHeight
  • Implémenter les méthodes delegate / dataSource (ie heightForRowAtet lui renvoyer une valeur UITableViewAutomaticDimension)

-

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

Rapide:

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

Pour l'instance d'étiquette dans UITableviewCell

  • Définir le nombre de lignes = 0 (& mode de saut de ligne = queue tronquée)
  • Définissez toutes les contraintes (haut, bas, droite gauche) par rapport à son conteneur superview / cell.
  • Facultatif : définissez la hauteur minimale de l'étiquette, si vous souhaitez que la zone verticale minimale soit couverte par l'étiquette, même en l'absence de données.

entrez la description de l'image ici

Remarque : Si vous avez plusieurs étiquettes (UIElements) avec une longueur dynamique, qui doit être ajustée en fonction de la taille de son contenu: ajustez la `` Priorité à l'étirement du contenu et à la résistance à la compression '' pour les étiquettes que vous souhaitez développer / compresser avec une priorité plus élevée.

Ici, dans cet exemple, j'ai défini une priorité de résistance à la compression faible et élevée, ce qui conduit à définir plus de priorité / importance pour le contenu de la deuxième étiquette (jaune).

entrez la description de l'image ici

Krunal
la source
5

Grâce à tous les articles sur ce sujet, il existe des moyens très utiles d'ajuster le rowHeight d'un UITableViewCell.

Voici une compilation de certains des concepts de tout le monde qui aide vraiment lors de la construction pour iPhone et iPad. Vous pouvez également accéder à différentes sections et les ajuster en fonction des différentes tailles de vues.

- (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;
} 
pourquoi
la source
Lors de l'analyse dans XCode, la ligne "int cellHeight;" a créé une erreur logique, "Valeur indéfinie ou incorrecte renvoyée à l'appelant." En définissant cellHeight sur 0, cela a corrigé l'erreur. Cette erreur apparaîtra également si vous ne définissez pas NSString sur nil dans une instruction switch similaire à l'instruction if / else if ci-dessus.
whyoz
3

Pour avoir la hauteur de cellule dynamique à mesure que le texte de Label augmente, vous devez d'abord calculer la hauteur, que le texte va utiliser dans la -heightForRowAtIndexPathméthode déléguée et la renvoyer avec les hauteurs ajoutées d'autres étiquettes, images (hauteur maximale du texte + hauteur des autres éléments statiques) composants) et utiliser la même hauteur dans la création de cellules.

#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
la source
@Tisho L'avez-vous testé Tisho bro pour voter contre. Testez soigneusement, cela fonctionne bro !!!!
Samir Jwarchan
1
Je n'ai pas diminué votre réponse. Je viens d'améliorer la mise en forme.
Tisho