60 votes

UITableView flexible / dynamique heightForRowAtIndexPath

Cas

Normalement vous devriez utiliser l' cellForRowAtIndexPath délégué de la méthode de configuration de votre cellule. Les informations à la cellule est important pour la façon dont la cellule est établi et que la taille sera.

Malheureusement, l' heightForRowAtIndexPath délégué méthode est appelée avant que l' cellForRowAtIndexPath délégué de la méthode on ne peut donc pas dire tout simplement le délégué de revenir à la hauteur de la cellule, car ce sera zéro à l'époque.

Nous avons donc besoin de calculer la taille avant de la cellule est établi dans le tableau. Heureusement, il existe une méthode qui ne fonctionne tout simplement que, sizeWithFont, qui appartient à la classe NSString. Cependant il y a un problème, pour le calcul de la taille correcte de façon dynamique, il a besoin de savoir comment les éléments de la cellule sera présenté. Je vais faire de ce clair dans un exemple:

Imaginez un UITableViewCell, qui contient une étiquette nommée textLabel. Au sein de l' cellForRowAtIndexPath délégué de la méthode que nous plaçons textLabel.numberOfLines = 0, qui raconte essentiellement l'étiquette, il peut avoir autant de lignes que nécessaire de présenter le texte pour une largeur spécifique. Le problème se produit si nous donnons textLabel un texte de plus de la largeur d'abord été donnés à textLabel. La deuxième ligne apparaît, mais la hauteur de la cellule ne sera pas ajusté automatiquement et on obtient un foiré à la recherche de table.

Comme dit précédemment, on peut utiliser sizeWithFont pour calculer la hauteur, mais il doit savoir quelle est la Police utilisée, pour la largeur, etc. Si, pour des raisons de simplicité, nous venons de soins sur la largeur, on pourrait coder en dur que la largeur doit être d'environ 320.0 (en ne prenant pas de rembourrage en considération). Mais qu'arriverait-il si nous avons utilisé UITableViewStyleGrouped au lieu de la plaine de la largeur serait alors autour de 300,0 et la cellule serait encore foiré. Ou ce qui se fait si on les échange de portrait à paysage, nous avons beaucoup plus d'espace, mais il ne sera pas utilisé depuis que nous avons codé en dur 300.0.

C'est le cas où, à un certain point, vous devez vous poser la question, combien pouvez-vous éviter de coder en dur.

Mes Propres Pensées

On pourrait appeler l' cellForRowAtIndexPath méthode qui appartient à la UITableView classe pour obtenir la cellule pour une section donnée et de la ligne. J'ai lu quelques posts qui dit que vous ne voulez pas le faire, mais je ne comprends pas vraiment. Oui, je suis d'accord c'est déjà allouer de la cellule, mais l' heightForRowAtIndexPath délégué de la méthode n'est appelée que pour les cellules qui seront visibles jusqu'à la cellule sera alloué de toute façon. Si vous l'utilisez correctement l' dequeueReusableCellWithIdentifier la cellule ne sera pas alloué de nouveau dans l' cellForRowAtIndexPath méthode, au lieu d'un pointeur est utilisé et les propriétés sont juste ajusté. Alors quel est le problème?

Notez que la cellule n'est PAS tracée à l'intérieur de l' cellForRowAtIndexPath délégué de la méthode, lorsque la vue de la table de la cellule devient visible le script appelle l' setNeedDisplay méthode sur la UITableVieCell qui déclenche l' drawRect méthode pour dessiner la cellule. Donc, l'appel de la cellForRowAtIndexPath délégué directement ne perdrez pas les performances, car il doit être établi, à deux reprises.

Ok, donc, en appelant l' cellForRowAtIndexPath délégué de la méthode au sein de l' heightForRowAtIndexPath délégué de la méthode que nous recevons toutes les informations dont nous avons besoin sur la cellule pour déterminer sa taille.

Peut-être que vous pouvez créer votre propre sizeForCell méthode qui s'exécute à travers toutes les options, si la cellule est en Valeur1 style, ou Valeur2, etc.

Conclusion/Question

C'est juste une théorie que j'ai décrit dans mes pensées, je voudrais savoir si ce que j'ai écrit est correct. Ou que peut-être il ya une autre façon de faire la même chose. Notez que je veux être capable de faire des choses aussi souple que possible.

26voto

omz Points 38947

Oui, je suis d'accord c'est déjà allouer de la cellule, mais la heightForRowAtIndexPath délégué méthode n'est appelée que pour les cellules qui seront visibles jusqu'à la cellule sera alloué de toute façon.

Ceci est incorrect. La vue de la table a besoin d' heightForRowAtIndexPath (s'il est mis en œuvre) pour toutes les lignes qui sont dans la vue de table, pas seulement celles qui sont actuellement affichés. La raison en est qu'il a besoin de comprendre à sa hauteur totale à l'affichage correct des indicateurs de défilement.

8voto

Jesse Armand Points 880

J'ai utilisé pour ce faire par:

  1. La création d'une collection d'objets (tableau de la taille de l'information (dictionnaire, NSNumber des hauteurs de ligne, etc.) basé sur la collection d'objets qui seront utilisés pour l'affichage de la table.

  2. Cela se fait lorsque nous traitons les données à partir d'un local ou à distance à la source.

  3. Je prédéterminer le type et la taille de la police de caractères qui sera utilisée, quand je suis à la création de cette collection d'objets. Vous pouvez même stocker les UIFont objets ou que ce soit des objets personnalisés utilisés pour représenter le contenu.

  4. Ces objets de collection seront utilisés chaque fois que j'en œuvre UITableViewDataSource ou UITableViewDelegate des protocoles afin de déterminer la taille de la UITableViewCell instances et de ses sous-vues, etc.

En le faisant de cette façon, vous pouvez éviter d'avoir à la sous-classe UITableViewCell juste pour obtenir les différentes propriétés de taille de son contenu.

N'utilisez pas une valeur absolue pour l'initialisation de la les cadres. Relatif à la valeur fondée sur l'orientation actuelle et les limites.

Si nous la faire pivoter pour n'importe quelle orientation, il suffit de faire un mécanisme de redimensionnement automatique lors de l'exécution. Assurez-vous que le autoresizingMask est correctement définie.

Vous avez seulement besoin de les hauteurs, vous n'avez pas besoin de tous que des choses inutiles à l'intérieur d'un UITableViewCell pour déterminer la hauteur de ligne. Vous pouvez même pas besoin de la largeur, parce que, comme je l'ai dit, la valeur de la largeur doit être relatif à la vue de limites.

7voto

Eric Points 3061

Voici ma démarche pour la résolution de ce

  1. Je suppose que dans cette solution qu'une seule Étiquette a une "dynamique" de hauteur
  2. J'ai aussi assumer si nous faisons l'étiquette de réglage de taille automatique pour étirer la hauteur de la cellule augmente seulement la hauteur de la cellule est nécessaire pour changer
  3. Je suppose que la plume a l'espacement approprié pour l'emplacement de l'étiquette sera et combien d'espace est ci-dessus et ci-dessous il
  4. Nous ne voulons pas changer le code de tous les temps on changer la police ou la position de l'étiquette dans la plume

Comment mettre à jour la hauteur:

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

    // We want the UIFont to be the same as what is in the nib,
    //  but we dont want to call tableView dequeue a bunch because its slow. 
    //  If we make the font static and only load it once we can reuse it every
    //  time we get into this method
    static UIFont* dynamicTextFont;
    static CGRect textFrame;
    static CGFloat extraHeight;
    if( !dynamicTextFont ) {
        DetailCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
        dynamicTextFont = cell.resizeLabel.font;
        CGRect cellFrame = cell.frame;
        textFrame = cell.resizeLabel.frame;
        extraHeight = cellFrame.size.height-textFrame.size.height; // The space above and below the growing field
    }
    NSString* text = .... // Get this from the some object using indexPath 

    CGSize  size = [text sizeWithFont:dynamicTextFont constrainedToSize:CGSizeMake(textFrame.size.width, 200000.f) lineBreakMode:UILineBreakModeWordWrap];

    return size.height+extraHeight;
}

Questions:

  • Si vous n'êtes pas à l'aide d'un prototype de cellule, vous aurez besoin de vérifier si la cellule est nul et il init
  • Votre plume / storyboard doit avoir la UILabel autosize et multi ligne mis à 0

4voto

MrMage Points 4695

Vous devriez jeter un oeil à TTTableItemCell.m dans le Three20 cadre. Il suit une approche différente, essentiellement par le fait d'avoir chaque cellule de la classe (avec certains paramètres prédéfinis comme la police, mise en page etc.) mettre en œuvre une méthode partagée + tableView: sizeForItem: (ou quelque chose comme ça), où il reçoit le texte dans l'élément de l'objet. Quand vous regardez le texte d'une cellule spécifique, vous pouvez ainsi rechercher la police appropriée, trop.

Concernant la hauteur de la cellule: Vous pouvez vérifier votre tableView de largeur et, si nécessaire, de soustraire la marge en UITableViewStyleGrouped et la largeur d'une éventuelle index de bar et de la divulgation de l'élément (que vous recherchez dans le stockage de données pour vos cellules de données). Lorsque la largeur de la tableView changements, par exemple par l'interface de rotation, vous appelez [tableView reloadData].

3voto

Rols Points 21

Pour répondre à la question de l'affiche originale a demandé qui était " est-il ok pour appeler cellForRowAtIndexPath?', il n'est pas. Cela vous donnera une cellule, mais il ne sera PAS les attribuer à qui indexPath à l'intérieur, ni qu'il sera re-file d'attente (pas de méthode pour le mettre à l'arrière), de sorte que vous aurez juste à le perdre. Je suppose que ce sera dans un autorelease pool et sera libéré par la suite, mais vous aurez encore à la création de charges de cellules, encore et encore, et c'est assez inutile.

Vous pouvez faire dynamique de la hauteur de cellule, vous pouvez même les faire look très agréable, mais c'est beaucoup de travail pour vraiment donner un aspect homogène, même plus si vous voulez prendre en charge de multiples orientations, etc.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X