Adapter la hauteur d'une ligne dans un NSTableView
colas_
Membre
Bonjour,
J'ai une NSTableView mais le texte à afficher est des fois long et des fois court.
Je voudrais donc que les "cases" de ma NSTableView soient plus ou moins hautes pour montrer tout le texte.
(PS : ma NSTableView est liée à un NSArrayController, mais éventuellement, je peux la datasourcer à la main)
Avez-vous une idée de comment faire ?
En cherchant sur le web, j'ai trouvé ceci :
cell.textLabel.numberOfLines = 0;
cell.textLabel.lineBreakMode = UILineBreakModeWordWrap;
(cf. http://stackoverflow.com/questions/5964448/ios-uitableview-cells-with-multiple-lines)
... que je devrais adapter pour osx.
Ma question à ce niveau est : à quel endroit du code puis insérer ce code ?
Dans une méthode du delegate ?
Y a-t-il une autre manière de faire ?
Merci !
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
ben je dirai dans ton datasource :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
Et il faudra surement régler la hauteur de ta ligne dans ton delegate :
tableView:heightForRowAtIndexPath:
Merci !
je vais essayer de juste toucher au delegate !
vaz y chaton
On a pas déjà évoqué les meilleures manières de comment résoudre ce pb dans d'autres threads ? (recherche ?)
C'est un cas assez classique, en utilisant les méthodes de "NSString UIKit Additions" pour connaà®tre la taille que prendra ton texte à l'écran (en largeur et hauteur) tu peux en déduire la hauteur de chaque cellule (suffit d'ajouter les marges que tu as entre ton UILabel et les bords de ta cellule) et implémenter heightForRowAtIndexPath.
J'ai déjà parlé il me semble de tous les tenants et aboutissants autour de cette problématique : suggestion d'implémentation, comment récupérer automatiquement les marges depuis un XIB si tes cells sont dans un XIB custom, comment mettre en cache ces données de marges, mettre en cache ces données de hauteur pour éviter de les recalculer à chaque scroll / reuse, ...
Si je veux suivre l'idée de http://stackoverflow.com/questions/5964448/ios-uitableview-cells-with-multiple-lines, comment puis-je modifier les attributs des cell de ma NSTableView ?
PS @Ali : Je n'ai pas trouvé tes posts...
Puisqu'on est dans Cocoa, ça devrait être la méthode:
- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
oups, sorry....
http://forum.cocoacafe.fr/topic/10103-heightforrowatindexpath-optimisation/?hl=heightforrowatindexpath
http://forum.cocoacafe.fr/topic/8097-hauteur-dune-cellule-dans-une-tableview/?hl=heightforrowatindexpath#entry78110
http://forum.cocoacafe.fr/topic/6153-definir-une-hauteur-de-cellule/?hl=heightforrowatindexpath#entry62122
....
Voici la réponse, basée sur ce post :
http://stackoverflow.com/questions/7504546/view-based-nstableview-with-rows-that-have-dynamic-heights
Idée : on calcule tout à la main.
Mais, on fait ce calcul sur une NSTextFieldCell qui est créée à part juste pour ce besoin !
Ici, la tableView est remplie via un NSArrayController.
Code dans le delegate :
puis
"exactement" est un peu exagéré ::)
Tu ne décris pas le mécanisme d'avoir une NSCell indépendante du NSTableView sous la main
pour faire le calcul de la hauteur qu'il faut choisir.
Cela ne t'enlève pas le mérite de tes nombreuses réponses. J'avais besoin d'une aide plus concrète car je n'avais jamais utilisé la classe NSCell : le mécanisme d'envoyer un NSRect à NSCell pour obtenir une NSSize, je ne l'aurai pas deviné (entre autres). L'occasion de te remercier grandement pour toutes les contributions que tu fais ici, toujours complètes et agréables à lire ! Merci !
Bah si, enfin j'explique l'équivalent sous iOS.
Et j'explique comment rendre ça plus propre même avec un dispatch_once pour n'instancier cette cellule depuis un UINib que quand c'est nécessaire (lazy-loading) et comment plutôt que garder une "UITableViewCell* dummyCellForSize" complète en mémoire il est mieux une fois qu'on l'a chargé et qu'on a récupéré toutes les marges et qu'on les a stocké dans une petite structure maison, on peut relâcher la cellule.
En gros
Bon c'est du code retapé en live et pas testé mais le principe est là : la première fois qu'on appelle cellSizeForText, on instancie la cell à l'aide du XIB, on récupère toutes les métriques dont on a besoin, les marges, la police, et pourquoi pas d'autres attributs qui nous seront nécessaires (le mode de wrapping du label par exemple, que je n'ai pas mis dans mon pseudo-code). Et une fois qu'on a ces éléments, plus besoin de la cellule (qui potentiellement prend de la place en mémoire, si elle a plein de sous-vues qui en plus contiennent des images ou autre, etc...), si la laisses s'autorelease, et tu ne gardes que les métriques comme margins ou labelFont, variables statiques donc dont tu garderas la valeur pour les appels suivants. Au final lors des autres appels tu auras déjà toutes les métriques qu'il te faut pour passer de la taille de ton texte à la taille de ta cellule, pas besoin de réinstancier une cellule depuis le XIB à chaque fois. Et pas besoin de garder la cellule entière dans une propriété non plus.Oui.
Remarque que ma NSCell supplémentaire n'est instanciée qu'une seule fois par la classe déléguée. Ce qui n'est pas énorme (du tout) !
Si on voulait faire une archi, on pourrait imaginer une méthode appartenant à ta classe héritant de NSCell et qui prendrait en argument un texte et une largeur, et qui renverrait une hauteur.
Heu... c'est exactement ce que je propose justement... Une méthode de classe de ma sous-classe de UITableViewCell (équivalent iOS de NSCell) qui renvoie la CGSize (et en effet je pourrais me contenter de la hauteur) en fonction du texte.
N'instancier qu'une seule fois ta NSCell peut ne pas te sembler énorme, mais ça dépend ce que contient ta NSCell (si elle a plein de subviews qui sont instanciées et qui dans leur constructeur crée aussi des objets internes et tout...). Avoir plein de NSView (la cell et ses subviews) + potentiellement des NSArray ou autres données internes instanciées par ton contenu de ta NSCell ça peut vite prendre de la place alors que tu n'en as cure. Alors qu'une bête structure qui ne stoque que 2-3 valeurs (les marges, la police de caractère utilisée, ...) c'est quand même vachement plus léger.
Au final j'explique dans mes posts toute l'architecture que j'utilise pour ça (et même en général j'ai une autre version si je veux optimiser je mets des constantes dans mon code et je fais ce bout de code qu'en debug avec un NSAssert pour vérifier que mes constantes sont consistantes avec le XIB, comme ça en Release c'est encore plus efficace et immédiat et en Debug il m'alerte tout de suite si j'ai modifié le XIB et oublié de modifier les constantes en conséquence...), mais bon j'ai déjà débattu et expliqué les pours et les contres et les inconvénients de telle méthode et pourquoi je propose telle solution à la place...
Autant pour moi !
PS : En voyant ta réponse je viens de relire la mienne à tête reposée et réalise qu'elle est un peu "sèche", désolé, ce n'était pas le but hein ^^