2012-04-23 6 views
21

J'ai un UITableView qui est rempli avec des cellules personnalisées (héritées de UITableViewCell), chaque cellule contient un UIWebView qui est automatiquement redimensionné en fonction de son contenu. Voici la chose, comment puis-je changer la hauteur des cellules UITableView en fonction de leur contenu (variable webView).Taille de cellule UITableView dynamique basée sur le contenu

La solution doit être dynamique car le code HTML utilisé pour remplir le UIWebViews est analysé à partir d'un flux en constante évolution.

Je sens que je dois utiliser la méthode délégué UITableViewheightForRowAtIndexPath mais de sa définition:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    ;//This needs to be variable 
} 

Je ne peux pas accéder à la cellule ou de son contenu. Puis-je changer la hauteur de la cellule en cellForRowAtIndexPath?

Toute aide serait grande. Merci.

Remarque

J'ai posé cette question il y a plus de 2 ans. Avec l'introduction de la mise en page automatique la meilleure solution pour iOS 7 se trouve:

http://t.co/PdUywcTjhu

et iOS8 cette fonctionnalité est intégrée dans le SDK

Répondre

17

La meilleure façon que je l'ai trouvé pour la hauteur dynamique est pour calculer la hauteur au préalable et la stocker dans une collection quelconque (probablement un tableau.) En supposant que la cellule contient principalement du texte, vous pouvez utiliser -[NSString sizeWithFont:constrainedToSize:lineBreakMode:] pour calculer la hauteur, puis renvoyer la valeur correspondante dans heightForRowAtIndexPath:

[MODIFIER ] Si le contenu est constamment chan ging, vous pouvez implémenter une méthode qui met à jour le tableau des hauteurs lorsque de nouvelles données ont été fournies.

+0

Merci, belle, je vais travailler là-dessus maintenant –

+0

"sizeWithFont" dépréciée de iOS 7. Utilisez plutôt "sizeWithAttributes". –

2

Voici le code que j'ai utilisé pour la hauteur de cellule dynamique lors de l'extraction de tweets de twitter, puis de les stocker dans CoreData pour une lecture hors ligne.

Non seulement ce spectacle comment obtenir le contenu des cellules et des données, mais aussi comment dimensionner dynamiquement une UILabel au contenu avec un rembourrage

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

    Tweet *tweet = [self.fetchedResultsController objectAtIndexPath:indexPath]; 

    NSString* text = tweet.Text; 

    TweetTableViewCell *cell = (TweetTableViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath]; 

    //Set the maximum size 
    CGSize maximumLabelSize = cell.tweetLabel.frame.size; 
    CGPoint originalLocation = cell.tweetLabel.frame.origin; 

    //Calculate the new size based on the text 
    CGSize expectedLabelSize = [text sizeWithFont:cell.tweetLabel.font constrainedToSize:maximumLabelSize lineBreakMode:cell.tweetLabel.lineBreakMode]; 


    //Dynamically figure out the padding for the cell 
    CGFloat topPadding = cell.tweetLabel.frame.origin.y - cell.frame.origin.y; 


    CGFloat bottomOfLabel = cell.tweetLabel.frame.origin.y + cell.tweetLabel.frame.size.height; 
    CGFloat bottomPadding = cell.frame.size.height - bottomOfLabel; 


    CGFloat padding = topPadding + bottomPadding; 


    CGFloat topPaddingForImage = cell.profileImage.frame.origin.y - cell.frame.origin.y; 
    CGFloat minimumHeight = cell.profileImage.frame.size.height + topPaddingForImage + bottomPadding; 

    //adjust to the new size 
    cell.tweetLabel.frame = CGRectMake(originalLocation.x, originalLocation.y, cell.tweetLabel.frame.size.width, expectedLabelSize.height); 


    CGFloat cellHeight = expectedLabelSize.height + padding; 

    if (cellHeight < minimumHeight) { 

     cellHeight = minimumHeight; 
    } 

    return cellHeight; 
} 
+7

L'appel 'cellForRowAtIndexPath:' depuis 'heightForRowAtIndexPath' n'est pas une bonne idée. Consultez cette réponse à la place: http://stackoverflow.com/a/5254852/969967 – Anthony

+1

Cette ligne: TweetTableViewCell * cell = (TweetTableViewCell *) [self tableView: tableView cellForRowAtIndexPath: indexPath]; dequeues rehusable rows ... – Lucas

2

Je pense aussi un tel algorithme vous convient:

1) cellForRowAtIndexPath vous activez votre webviews pour le chargement et leur donner des balises égales à indexPath.row

2) webViewDidFinishLoading calculer la hauteur du contenu de la cellule, et composer un dictionnaire avec les touches et des valeurs telles que ceci: clé = valeur indexPath.row = hauteur

3) appeler [tableview reloadData]

4) [tableview cellForRowAtIndexPath: indexPath] réglé hauteurs appropriées pour les cellules correspondantes

2

Le gros problème avec les cellules avec La hauteur dynamique dans iOS est que la table vc doit calculer et renvoyer une hauteur de chaque cellule avant que les cellules soient dessinées. Cependant, avant qu'une cellule ne soit dessinée, elle n'a pas de cadre et donc pas de largeur.Cela provoque un problème si votre cellule doit changer sa hauteur en fonction, disons, de la quantité de texte dans le libellé, puisque vous ne connaissez pas sa largeur.

Une solution courante que j'ai vu est que les gens définissent une valeur numérique pour la largeur de la cellule. C'est une mauvaise approche, car les tables peuvent être unies ou groupées, utiliser le style iOS 7 ou iOS 6, être affichées sur un iPhone ou un iPad, en mode paysage ou portrait, etc

J'ai eu des problèmes avec ces applications dans une application iOS à moi, qui supporte iOS5 + et à la fois iPhone et iPad avec de multiples orientations. J'avais besoin d'un moyen pratique d'automatiser cela et de laisser la logique hors du contrôleur de vue. Le résultat est devenu une sous-classe UITableViewController (de sorte qu'il peut contenir l'état) qui prend en charge les cellules par défaut (style par défaut et sous-titre) ainsi que les cellules personnalisées.

Vous pouvez l'attraper chez GitHub (https://github.com/danielsaidi/AutoSizeTableView). J'espère que cela aidera ceux d'entre vous qui luttent encore avec ce problème. Si vous le faites, j'aimerais entendre ce que vous en pensez et si cela a fonctionné pour vous.

4

J'ai essayé plusieurs solutions, mais celui qui a travaillé était cela, suggéré par un ami:

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

    int height = [StringUtils findHeightForText:yourLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:17.0f]]; 

    height += [StringUtils findHeightForText:yourOtherLabel havingWidth:yourWidth andFont:[UIFont systemFontOfSize:14.0f]]; 

    return height + CELL_SIZE_WITHOUT_LABELS; //important to know the size of your custom cell without the height of the variable labels 
} 

La classe StringUtils.h:

#import <Foundation/Foundation.h> 

@interface StringUtils : NSObject 

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font; 

@end 

classe StringUtils.m:

#import "StringUtils.h" 

@implementation StringUtils 

+ (CGFloat)findHeightForText:(NSString *)text havingWidth:(CGFloat)widthValue andFont:(UIFont *)font { 
    CGFloat result = font.pointSize+4; 
    if (text) { 
     CGSize size; 

     CGRect frame = [text boundingRectWithSize:CGSizeMake(widthValue, CGFLOAT_MAX) 
              options:NSStringDrawingUsesLineFragmentOrigin 
             attributes:@{NSFontAttributeName:font} 
              context:nil]; 
     size = CGSizeMake(frame.size.width, frame.size.height+1); 
     result = MAX(size.height, result); //At least one row 
    } 
    return result; 
} 

@end 

Cela a fonctionné parfaitement pour moi. J'ai eu une cellule personnalisée avec 3 images avec des tailles fixes, 2 étiquettes avec des tailles fixes et 2 étiquettes variables. Travaillé comme un charme. J'espère que ça marchera pour toi aussi.

Cordialement, Alexandre.

22

Cela fonctionne généralement assez bien:

Objective-C:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return UITableViewAutomaticDimension; 
} 

Swift:

override func tableView(tableView: UITableView!, heightForRowAtIndexPath indexPath: NSIndexPath!) -> CGFloat { 
    return UITableViewAutomaticDimension; 
} 
+0

Exactement ce dont j'avais besoin. – adrian1kat

+5

Cela ne fonctionnera pas dans ios9 – Bangalore

+2

cela fonctionne avec ios9, vous devrez peut-être fournir la hauteur maximale estimée dans la fonction tableview ** "estimatedHeightForRowAtIndexPath" ** – LuAndre

0

je mets en œuvre toujours ce dans toutes mes cellules dans une classe super cellulaire parce que pour certains raison UITableViewAutomaticDimension ne fonctionne pas très bien.

-(CGFloat)cellHeightWithData:(id)data{ 
    CGFloat height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 
    [self fillCellWithData:data]; //set the label's text or anything that may affect the size of the cell 
    [self layoutIfNeeded]; 
    height = [[self contentView] systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height; 
    return height+1; //must add one because of the cell separator 
} 

simplement appeler cette méthode sur votre -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath en utilisant une cellule fictive.

note: cela fonctionne uniquement avec autolayout, mais il fonctionne également avec ios 7 et versions ultérieures.

pd: ne pas oublier de cocher la case sur le story-board ou xib pour "largeur préférée explicite" et définir la largeur statique (sur les cmd + alt + 5 Menu)

4
self.tblVIew.estimatedRowHeight = 500.0; // put max you expect here. 
self.tblVIew.rowHeight = UITableViewAutomaticDimension; 
0

Swift Utilisez une cellule et des étiquettes personnalisées. Configurez les contraintes pour UILabel.(En haut, à gauche, en bas, à droite) Définir des lignes du UILabel à 0

Ajoutez le code suivant dans la méthode viewDidLoad du ViewController:

tableView.estimatedRowHeight = 68.0 
tableView.rowHeight = UITableViewAutomaticDimension 

// délégué & source de données

override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { 
    return UITableViewAutomaticDimension; 
} 
0

J'ai eu un très gros test dans UILabel. Surtout ne fonctionnent pas, alors je crée la catégorie pour la chaîne comme ci-dessous et a obtenu la hauteur exacte

- (CGFloat)heightStringWithEmojifontType:(UIFont *)uiFont ForWidth:(CGFloat)width { 

// Get text 
CFMutableAttributedStringRef attrString = CFAttributedStringCreateMutable(kCFAllocatorDefault, 0); 
CFAttributedStringReplaceString (attrString, CFRangeMake(0, 0), (CFStringRef) self); 
CFIndex stringLength = CFStringGetLength((CFStringRef) attrString); 

// Change font 
CTFontRef ctFont = CTFontCreateWithName((__bridge CFStringRef) uiFont.fontName, uiFont.pointSize, NULL); 
CFAttributedStringSetAttribute(attrString, CFRangeMake(0, stringLength), kCTFontAttributeName, ctFont); 

// Calc the size 
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(attrString); 
CFRange fitRange; 
CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, CFRangeMake(0, 0), NULL, CGSizeMake(width, CGFLOAT_MAX), &fitRange); 

CFRelease(ctFont); 
CFRelease(framesetter); 
CFRelease(attrString); 

return frameSize.height + 10;} 
0

C'est l'une de ma belle solution. ça a marché pour moi.

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 
    cell.textLabel.text = [_nameArray objectAtIndex:indexPath.row]; 
    cell.textLabel.numberOfLines = 0; 
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping; 
} 

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return UITableViewAutomaticDimension; 
} 

Nous devons appliquer ces 2 changements.

1)cell.textLabel.numberOfLines = 0; 
    cell.textLabel.lineBreakMode = NSLineBreakByWordWrapping; 

2)return UITableViewAutomaticDimension; 
Questions connexes