web-dev-qa-db-fra.com

UITableViewCell avec hauteur dynamique iOS

J'ai implémenté TableView avec CustomCell dans mon application,

Je veux la hauteur dynamique de mon UITableViewCell en fonction de la longueur du texte dans UITableViewCell,

voici l'instantané de Customcell

: et voici l'instantané de mon UITableView : extrait de code pour heightForRowAtIndexPath

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

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
{
    NSString *text = [DescArr objectAtIndex:[indexPath row]];
    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, 100.0);
    return height; 
}

Comme vous pouvez le voir sur la 2e image, la hauteur de la cellule est fixe, elle ne change pas avec sa taille de texte (contenu).

Où est-ce que je me trompe? Comment puis-je créer une étiquette ou une cellule pour mettre à jour sa taille en fonction de son contenu/texte?

11
Krunal

Le code suivant a bien fonctionné pour moi.

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

    CGFloat lRetval = 10;
    CGSize maximumLabelSize = CGSizeMake(231, FLT_MAX);
    CGSize expectedLabelSize;


    CGFloat numberoflines = [thirdcellText length]/17.0;

    if (indexPath.section == 0) {
        expectedLabelSize = [firstcellText sizeWithFont:[UIFont systemFontOfSize:16.0]
                                      constrainedToSize:maximumLabelSize
                                          lineBreakMode:NSLineBreakByWordWrapping];
        lRetval = expectedLabelSize.height;
    }
    else if(indexPath.section == 1)
    {
        expectedLabelSize = [secondcellText sizeWithFont:[UIFont systemFontOfSize:16.0]
                                       constrainedToSize:maximumLabelSize
                                           lineBreakMode:NSLineBreakByWordWrapping];
        lRetval = expectedLabelSize.height;
    }
    else if (indexPath.section == 2)
    {
        expectedLabelSize = [thirdcellText sizeWithFont:[UIFont systemFontOfSize:16.0]
                                       constrainedToSize:CGSizeMake(231, numberoflines*17.0)
                                           lineBreakMode:NSLineBreakByWordWrapping];
        lRetval = expectedLabelSize.height-128.0;
    }

    UIImage *factoryImage = [UIImage imageNamed:NSLocalizedString(@"barcode_factory_reset.png", @"")];

    CGFloat height = factoryImage.size.height;

    if (lRetval < height) {
        lRetval = height+15.0;
    }

    return lRetval;
}

Essayez d'ajouter le code suivant dans votre méthode de mise en page automatique de classe de cellule personnalisée

textview.frame = frame;
CGRect frame1 = textview.frame;
frame1.size.height = textview.contentSize.height-2;
textview.frame = frame1;


textview.contentSize = CGSizeMake(textview.frame.size.width, textview.frame.size.height);

labelPtr.frame = CGRectMake(CGRectGetMinX(imageView.frame)+CGRectGetMaxX(imageView.frame)+5.0, textview.frame.size.height+10.0, 140, 16.0);
[labelPtr setNeedsDisplayInRect:labelPtr.frame];

Essayez de définir les propriétés de l'étiquette comme suit

labelPtr = [[UILabel alloc] initWithFrame:CGRectZero];
labelPtr.backgroundColor =[UIColor clearColor];
[labelPtr setNeedsLayout];
[labelPtr setNeedsDisplay];
[self.contentView addSubview:labelPtr];
6
NHS

S'il vous plaît, regardez ICI - Tutoriel sur la hauteur dynamique des cellules et la disposition automatique de la table.

De quoi as-tu besoin:

  • définissez la contrainte requise sur les éléments de la cellule (assurez-vous que tout est fait correctement, sinon - vous pouvez obtenir beaucoup de problèmes). Assurez-vous également que vous définissez IntrinsicSize sur la valeur PlaceHolder

enter image description here

  • ajouter quelques méthodes pour calculer la taille de la cellule

Méthodes:

//this will calculate required height for your cell
-(CGFloat)heightForBasicCellAtIndexPath:(NSIndexPath *)indexPath {
      static UIYourClassCellName *sizingCell = nil;
      //create just once per programm launching
      static dispatch_once_t onceToken;
      dispatch_once(&onceToken, ^{
      sizingCell = [self.tableView dequeueReusableCellWithIdentifier:@"identifierOfCell"];
});
  [self configureBasicCell:sizingCell atIndexPath:indexPath];
  return [self calculateHeightForConfiguredSizingCell:sizingCell];
}
//this method will calculate required height of cell
- (CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell {
      [sizingCell setNeedsLayout];
      [sizingCell layoutIfNeeded];
      CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
      return size.height;
}

Et appeler

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

Configuration de la cellule

- (void)configureBasicCell:(RWBasicCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    //make some configuration for your cell
}

Après toute opération, je suis passé (texte à l'intérieur de la cellule uniquement comme espace réservé):

enter image description here

13
gbk

Je cherche depuis longtemps à déterminer correctement la hauteur des cellules, - semble - c'est une meilleure solution, boundingRectWithSize et constrainedToSize souvent la hauteur de texte incorrectement calculée, vous devez créer UILabel que d'utiliser la fonction sizeThatFits, voir ci-dessous

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

    UILabel  * label = [[UILabel alloc] initWithFrame:CGRectMake(8, 5, celllabelWidth, 9999)];
    label.numberOfLines=0;
    label.font = [UIFont fontWithName:fontName size:textSize];
    label.text = @"celllabelTextHere";

    CGSize maximumLabelSize = CGSizeMake(celllabelWidth, 9999);
    CGSize expectedSize = [label sizeThatFits:maximumLabelSize];
    return expectedSize.height;
}
5
user2154220

C'est très simple maintenant
Utilisez les étapes ci-dessous

  1. Définissez une contrainte sur votre étiquette (si vous utilisez une cellule personnalisée)
  2. Le nombre de ligne doit être 0
  3. Configurer quelques propriétés de UITableView

self.tableView.estimatedRowHeight = 100.0;
self.tableView.rowHeight = UITableViewAutomaticDimension;

Prendre plaisir:)
Pour plus de détails, vous pouvez vérifier
www.raywenderlich.com
stackoverflow.com

5
Tarun Seera

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 bas de l'étiquette (contraindre) rétrograder "Priorité à l'étirement du contenu - Vertical à 250"

enter image description hereenter image description here

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

Références: http://candycode.io/automatically-resizing-uitableviewcells-with-dynamic-text-height-using-auto-layout/

5
Jose Pose S

Pourriez-vous essayer ceci;

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
     int topPadding = cell.yourLabel.frame.Origin.x;
     int bottomPadding = cell.frame.size.heigth-(topPadding+cell.yourLabel.frame.size.height);
     NSString *text = [DescArr objectAtIndex:[indexPath row]];
     CGSize maximumSize = CGSizeMake(cell.yourLabel.frame.size.width, 9999);
     CGSize expectedSize = [text sizeWithFont:yourCell.yourLabel.font constrainedToSize:maximumSize lineBreakMode:yourCell.yourLabel.lineBreakMode];

     return topPadding+expectedSize.height+bottomPadding;
}
3
Engnyl

Référez-vous à ce lien que vous utilisez Autolayout

sinon vous pouvez utiliser l'approche ci-dessous

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


NewsVCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];

if (cell == nil)
{

    cell = [[NewsVCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];

}

cell.titleCell.numberOfLines = 0;
cell.descriptionCell.numberOfLines = 0;

cell.titleCell.font = [UIFont systemFontOfSize:12.0f];
cell.descriptionCell.font = [UIFont systemFontOfSize:12.0f];

cell.descriptionCell.textColor = [UIColor lightGrayColor];


CGSize maximumLabelSize;

if([UIDevice currentDevice].userInterfaceIdiom==UIUserInterfaceIdiomPad || [[[UIDevice currentDevice] model] isEqualToString:@"iPad Simulator"])
{
    maximumLabelSize = CGSizeMake(768, 10000);

}
else
{
    maximumLabelSize = CGSizeMake(270, 10000);

}

NSString *newsTitle =  [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];

NSString *descriptionsText = [[feeds objectAtIndex:indexPath.row] objectForKey: @"description"];


CGSize expectedTitleLabelSize = [newsTitle sizeWithFont: cell.titleCell.font constrainedToSize:maximumLabelSize lineBreakMode:cell.titleCell.lineBreakMode];

CGSize expectedDescriptionLabelSize = [descriptionsText sizeWithFont:cell.descriptionCell.font constrainedToSize:maximumLabelSize lineBreakMode:cell.descriptionCell.lineBreakMode];

NSLog(@"cellForRowAtIndexPath :indexpath.row %d: height expectedTitleLabelSize:%f , indexpath.row height expectedDescriptionLabelSize:%f",indexPath.row,expectedTitleLabelSize.height,expectedDescriptionLabelSize.height);



if (newsTitle.length > 0)
{

    cell.titleCell.frame = CGRectMake(20.0f, 10.0f, 270.0f ,expectedTitleLabelSize.height+20.0f);

}
else
{
     cell.titleCell.frame = CGRectMake(20.0f, 10.0f, 270.0f ,expectedTitleLabelSize.height-20.0f);
}


if (descriptionText.length > 0)
{
    cell.descriptionCell.frame =  CGRectMake(20.0f, 10.0f + cell.titleCell.frame.size.height, 270.0f, expectedDescriptionLabelSize.height+20.0f);

}
else
{
    cell.descriptionCell.frame =  CGRectMake(20.0f, cell.titleCell.frame.size.height, 270.0f, 0.0f);

}


  cell.descriptionCell.frame =  CGRectMake(20.0f, 10.0f + cell.titleCell.frame.size.height, 270.0f, expectedDescriptionLabelSize.height+20.0f);

cell.titleCell.text = newsTitle;
cell.descriptionCell.text = descriptionsText;

NSLog(@"indexpath.row %d :title %@ ",indexPath.row,newsTitle);

NSLog(@"indexpath.row %d :description %@",indexPath.row,descriptionsText);

return cell;

 }

marque pragma - UITableViewDelegate

   - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
 {
float totalHeight = 0.0f;

UILabel *labelTitle;


CGSize maximumLabelSize;


if([UIDevice currentDevice].userInterfaceIdiom==UIUserInterfaceIdiomPad || [[[UIDevice currentDevice] model] isEqualToString:@"iPad Simulator"])
{
    labelTitle = [[UILabel alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 692.0f, 20.0f)];  // iPad
    maximumLabelSize = CGSizeMake(768.0f, 10000.0f);

}
else
{
    labelTitle = [[UILabel alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 270.0f, 20.0f)];
    maximumLabelSize = CGSizeMake(270.0f, 10000.0f);

}



labelTitle.font = [UIFont systemFontOfSize:12.0f];


NSString *newsTitle;
NSString *newsDescription;

  //  cell.titleCell.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];
  //   cell.descriptionCell.text = [[feeds objectAtIndex:indexPath.row] objectForKey: @"description"];



    newsTitle = [[feeds objectAtIndex:indexPath.row] objectForKey: @"title"];

    newsDescription = [[feeds objectAtIndex:indexPath.row] objectForKey: @"description"];

NSLog(@"indexpath.row %d :newsDescription.length %d",indexPath.row,newsDescription.length);
CGSize expectedTitleLabelSize;
CGSize expectedDescriptionLabelSize;


if (newsTitle.length > 0)
{
    expectedTitleLabelSize = [newsTitle sizeWithFont:labelTitle.font constrainedToSize:maximumLabelSize lineBreakMode:labelTitle.lineBreakMode];
    totalHeight = totalHeight + 20.0f;
}
else
{
    expectedTitleLabelSize = CGSizeMake(0.0f, 0.0f);
    totalHeight = -20.0f;
}

if (newsDescription.length > 0)
{
    expectedDescriptionLabelSize = [newsDescription sizeWithFont:labelTitle.font constrainedToSize:maximumLabelSize lineBreakMode:labelTitle.lineBreakMode];
    totalHeight = totalHeight + 20.0f;

}
else
{
    expectedDescriptionLabelSize = CGSizeMake(0.0f, 0.0f);
    totalHeight = -20.0f;
}


//  NSLog(@"question: %f title:%f",expectedQuestionLabelSize.height,expectedTitleLabelSize.height);

totalHeight = expectedDescriptionLabelSize.height + expectedTitleLabelSize.height + 30.0f+20.0f;




return totalHeight;

 }
2
bhavya kothari

Si vous souhaitez limiter la hauteur maximale à 100 pt, vous devez utiliser MIN à la place sur MAX:

CGFloat height = fmin(size.height, 100.0);
1
Nikolai Ruhe

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 & estimeRowHeight
  • Implémentez les méthodes delegate/dataSource (c'est-à-dire heightForRowAt et renvoyez-lui une valeur 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
    // Swift 4.2 onwards
    table.rowHeight = UITableView.automaticDimension
    table.estimatedRowHeight = UITableView.automaticDimension


    // Swift 4.1 and below
    table.rowHeight = UITableViewAutomaticDimension
    table.estimatedRowHeight = UITableViewAutomaticDimension

}



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

    // Swift 4.1 and below
    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 pour l'étiquette, si vous souhaitez que la zone verticale minimale soit couverte par l'étiquette, même s'il n'y a pas de données.

enter image description here

1
Krunal

Essayez ceci, cela a fonctionné comme un charme! pour moi,

Dans viewDidLoad, écrivez ce code,

-(void)viewDidLoad 
{
[super viewDidLoad];
 self.tableView.estimatedRowHeight = 100.0; // for example. Set your average height
 self.tableView.rowHeight = UITableViewAutomaticDimension;
}

Dans cellForRowAtIndexPath écrivez ce code,

 -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
 {
  static NSString *CellIdentifier = @"Cell";
  UITableViewCell *cell = [tableView 
  dequeueReusableCellWithIdentifier:CellIdentifier];
 if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] ;
  }
    cell.textLabel.numberOfLines = 0; // Set label number of line to 0
    cell.textLabel.text=[[self.arForTable objectAtIndex:indexPath.row] valueForKey:@"menu"];
    [cell.textLabel sizeToFit]; //set size to fit 
    return cell;
 }

J'espère que cela aidera quelqu'un.

0
Jaywant Khedkar

J'avais besoin d'une hauteur de cellule de vue de tableau dynamique basée sur la quantité de texte à afficher dans cette cellule. Je l'ai résolu de cette façon:

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

            if ([self.conditionsDataArray count]>0)
            {
                Conditions *condition =[self.conditionsDataArray objectAtIndex:indexPath.row];
                int height;
                UITextView *textview = [[UITextView alloc] initWithFrame:CGRectMake(0, 0, 236, 0)];   //you can set your frame according to your need
                textview.text  = condition.comment;
                textview.autoresizingMask = UIViewAutoresizingFlexibleHeight;
                [tableView addSubview:textview];
                textview.hidden = YES;
                height = textview.contentSize.height;
                NSLog(@"TEXT VIEW HEIGHT %f", textview.contentSize.height);
                [textview removeFromSuperview];
                [textview release];
                return height;
       }
       return 55;  //Default height, if data is in loading state
}

Notez que la vue texte a été ajoutée en tant que sous-vue, puis masquée. Assurez-vous donc de l'ajouter en tant que sous-vue, sinon sa hauteur ne sera pas prise en compte.

0
Jamal Zafar

Je viens d'écrire sur ce problème et l'approche que j'ai finalement choisie. Vous pouvez lire à ce sujet ici: Hauteur de cellule UITableView dynamique basée sur le conten

Fondamentalement, j'ai créé une sous-classe UITableView qui gère tout cela pour les cellules par défaut et personnalisées. Il a probablement besoin d'être peaufiné, mais je l'ai utilisé tel quel avec un bon résultat.

Vous pouvez récupérer le code ici: https://github.com/danielsaidi/DSTableViewWithDynamicHeight

J'espère que ça aide (... et si ce n'est pas le cas, je m'excuse et j'aimerais entendre pourquoi pas)

0
Daniel Saidi