88 votes

Selon la vue NSTableView avec des lignes dynamiques hauteurs

J'ai une application avec une vue basée sur NSTableView. À l'intérieur de ce tableview, j'ai des lignes qui ont des cellules qui ont un contenu consistant en un multi-ligne NSTextField avec word-wrap activé. Selon le contenu textuel de la NSTextField, la taille des lignes nécessaires à l'affichage de la cellule varie.

Je sais que je peux mettre en œuvre les NSTableViewDelegate de la méthode tableView:heightOfRow: retour à la hauteur, mais la hauteur sera déterminée sur la base du mot d'emballage utilisé sur la NSTextField. Le mot d'habillage de la NSTextField est de même en fonction de la largeur de la NSTextField est... qui est déterminé par la largeur de la NSTableView.

Soooo.... Je suppose que ma question est... qu'est ce qu'un bon modèle de conception pour cela? Il semble que tout ce que j'ai essayer vents est un alambiqué mess. Depuis la TableView nécessite la connaissance de la taille des cellules à jeter... et la NSTextField besoin de connaissance de la disposition pour déterminer le retour... et la cellule a besoin de connaissance de la parole écharpe pour déterminer la hauteur... c'est une circulaire gâchis... et ça me conduire fou.

Des Suggestions?

Si c'est important, le résultat final sera également modifiable NSTextFields que les redimensionner pour ajuster le texte à l'intérieur d'eux. J'ai déjà ce travail sur le niveau de la vue, mais la tableview n'a pas encore de régler la hauteur des cellules. J'ai la figure dès que j'arrive à la hauteur de l'enjeu travaillé, je vais utiliser l'-noteHeightOfRowsWithIndexesChanged méthode pour informer le tableview la hauteur changé... mais c'est encore d'aller demander au délégué à la hauteur... donc, mon quandry.

Merci à l'avance!

134voto

corbin dunn Points 716

C'est la poule et de l'œuf problème. La table a besoin de connaître la hauteur de ligne parce que détermine les cas où une vue mensonge. Mais vous voulez une vue d'ores et déjà être autour de sorte que vous pouvez l'utiliser pour déterminer la hauteur de ligne. Donc, ce qui vient en premier?

La réponse est de garder un extra - NSTableCellView (ou ce que vous utilisez comme votre "vue sur les cellules") autour juste pour la mesure de la hauteur de la vue. Dans l' tableView:heightOfRow: délégué de la méthode, l'accès à votre modèle pour la "rangée" et l' objectValue sur NSTableCellView. Ensuite, réglez le point de vue de la largeur de votre table de largeur, et (cependant, vous voulez faire) comprendre la hauteur de ce point de vue. De retour de cette valeur.

Ne pas appeler à l' noteHeightOfRowsWithIndexesChanged: à partir de la méthode du délégué tableView:heightOfRow: ou viewForTableColumn:row: ! Ce qui est mauvais, et sera la cause de méga-problème.

Mise à jour dynamique de la hauteur, puis ce que vous devez faire est de répondre au texte de modifier (via la cible de l'action) et de recalculer votre calculée à la hauteur de ce point de vue. Maintenant, ne pas modifier dynamiquement l' NSTableCellViews'hauteur (ou ce que vous utilisez comme votre "vue sur les cellules"). La table doit contrôler que la vue de l'image, et vous serez en lutte contre la tableview si vous essayez de le régler. Au lieu de cela, dans votre cible/action pour le champ de texte où vous avez calculé la hauteur, appelez - noteHeightOfRowsWithIndexesChanged:, qui laissera le redimensionnement du tableau que ligne individuelle. En supposant que vous avez votre d'un redimensionnement automatique de masque de configuration du bouton droit sur la sous-vues (c'est à dire: les sous-vues de l' NSTableCellView), les choses devraient redimensionner bien! Si pas, les premiers travaux sur le redimensionnement de masque de sous-vues de faire les choses avec la variable de la ligne des hauteurs.

N'oubliez pas que l' noteHeightOfRowsWithIndexesChanged: anime par défaut. Faire ne pas les animer:

[NSAnimationContext beginGrouping];
[[NSAnimationContext currentContext] setDuration:0];
[tableView noteHeightOfRowsWithIndexesChanged:indexSet];
[NSAnimationContext endGrouping];

PS: je de répondre aux questions postées sur le Dev Apple Forums de débordement de la pile.

PSS: j'ai écrit de la vue en fonction NSTableView

7voto

Sunkas Points 791

Pour ceux qui veulent plus de code, voici la solution que j'ai utilisée. Grâce corbin dunn pour me pointer dans la bonne direction.

J'avais besoin de régler la hauteur surtout en ce qui concerne la NSTextView mon NSTableViewCell a été.

Dans mon sous-classe de la NSViewController I temporaire de créer une nouvelle cellule en appelant outlineView:viewForTableColumn:item:

- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
    NSTableColumn *tabCol = [[outlineView tableColumns] objectAtIndex:0];
    IBAnnotationTableViewCell *tableViewCell = (IBAnnotationTableViewCell*)[self outlineView:outlineView viewForTableColumn:tabCol item:item];
    float height = [tableViewCell getHeightOfCell];
    return height;
}

- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
    IBAnnotationTableViewCell *tableViewCell = [outlineView makeViewWithIdentifier:@"AnnotationTableViewCell" owner:self];
    PDFAnnotation *annotation = (PDFAnnotation *)item;
    [tableViewCell setupWithPDFAnnotation:annotation];
    return tableViewCell;
}

Dans mon IBAnnotationTableViewCell qui est le contrôleur de ma cellule (sous-classe de la NSTableCellView) j'ai une méthode de configuration

-(void)setupWithPDFAnnotation:(PDFAnnotation*)annotation;

qui met en place tous les points de vente et définit le texte à partir de mon PDFAnnotations. Maintenant, je peux "facilement" calcutate la hauteur à l'aide:

-(float)getHeightOfCell
{
    return [self getHeightOfContentTextView] + 60;
}

-(float)getHeightOfContentTextView
{
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:[self.contentTextView font],NSFontAttributeName,nil];
    NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:[self.contentTextView string] attributes:attributes];
    CGFloat height = [self heightForWidth: [self.contentTextView frame].size.width forString:attributedString];
    return height;
}

.

- (NSSize)sizeForWidth:(float)width height:(float)height forString:(NSAttributedString*)string
{
    NSInteger gNSStringGeometricsTypesetterBehavior = NSTypesetterLatestBehavior ;
    NSSize answer = NSZeroSize ;
    if ([string length] > 0) {
        // Checking for empty string is necessary since Layout Manager will give the nominal
        // height of one line if length is 0.  Our API specifies 0.0 for an empty string.
        NSSize size = NSMakeSize(width, height) ;
        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:size] ;
        NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:string] ;
        NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init] ;
        [layoutManager addTextContainer:textContainer] ;
        [textStorage addLayoutManager:layoutManager] ;
        [layoutManager setHyphenationFactor:0.0] ;
        if (gNSStringGeometricsTypesetterBehavior != NSTypesetterLatestBehavior) {
            [layoutManager setTypesetterBehavior:gNSStringGeometricsTypesetterBehavior] ;
        }
        // NSLayoutManager is lazy, so we need the following kludge to force layout:
        [layoutManager glyphRangeForTextContainer:textContainer] ;

        answer = [layoutManager usedRectForTextContainer:textContainer].size ;

        // Adjust if there is extra height for the cursor
        NSSize extraLineSize = [layoutManager extraLineFragmentRect].size ;
        if (extraLineSize.height > 0) {
            answer.height -= extraLineSize.height ;
        }

        // In case we changed it above, set typesetterBehavior back
        // to the default value.
        gNSStringGeometricsTypesetterBehavior = NSTypesetterLatestBehavior ;
    }

    return answer ;
}

.

- (float)heightForWidth:(float)width forString:(NSAttributedString*)string
{
    return [self sizeForWidth:width height:FLT_MAX forString:string].height ;
}

2voto

laurent Points 29

Voici ce que j'ai fait pour résoudre le problème:

Source: Regarder dans XCode documentation, sous la rubrique "hauteur de ligne nstableview". Vous trouverez un exemple de code source nommée "TableViewVariableRowHeights/TableViewVariableRowHeightsAppDelegate.m"

(Note: je suis à la recherche à la colonne 1 du tableau de la vue, vous aurez à régler pour chercher ailleurs)

dans Délégué.h

IBOutlet NSTableView            *ideaTableView;

dans Délégué.m

la vue de la table des délégués de contrôle de hauteur de ligne

    - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row {
    // Grab the fully prepared cell with our content filled in. Note that in IB the cell's Layout is set to Wraps.
    NSCell *cell = [ideaTableView preparedCellAtColumn:1 row:row];

    // See how tall it naturally would want to be if given a restricted with, but unbound height
    CGFloat theWidth = [[[ideaTableView tableColumns] objectAtIndex:1] width];
    NSRect constrainedBounds = NSMakeRect(0, 0, theWidth, CGFLOAT_MAX);
    NSSize naturalSize = [cell cellSizeForBounds:constrainedBounds];

    // compute and return row height
    CGFloat result;
    // Make sure we have a minimum height -- use the table's set height as the minimum.
    if (naturalSize.height > [ideaTableView rowHeight]) {
        result = naturalSize.height;
    } else {
        result = [ideaTableView rowHeight];
    }
    return result;
}

vous avez également besoin de ceci pour effet la nouvelle hauteur de ligne (délégué de la méthode)

- (void)controlTextDidEndEditing:(NSNotification *)aNotification
{
    [ideaTableView reloadData];
}

J'espère que cette aide.

Dernière remarque: ce n'est pas en charge la modification de la largeur de la colonne.

2voto

Tim Points 1078

Avez-vous eu un coup d'oeil à RowResizableViews? Il est assez ancien et je n'ai pas testé, mais il peut néanmoins travailler.

0voto

vagrant Points 342

Cela ressemble beaucoup à quelque chose que j'ai eu à le faire auparavant. Je souhaite que je pourrais vous dire que je suis venu avec une solution simple et élégante, mais, hélas, je n'ai pas. Pas faute d'avoir essayé pourtant. Comme vous l'avez déjà remarqué la nécessité de UITableView de connaître la hauteur avant de les cellules de être construits vraiment de faire tout cela semble tout à fait circulaire.

Mon meilleur solution était de pousser la logique de la cellule, parce qu'au moins j'ai pu isoler la classe nécessaire pour comprendre comment les cellules ont été fixées. Une méthode comme

+ (CGFloat) heightForStory:(Story*) story

serait en mesure de déterminer quelle est la taille de la cellule devait être. Bien sûr qu'impliqué la mesure de texte, etc. Dans certains cas, j'ai trouvé le moyen de cacher de l'information acquise au cours de cette méthode qui peut alors être utilisé lorsque la cellule a été créée. C'était le meilleur que j'ai trouvé. Il est exaspérant de problème même si, comme il semble qu'il devrait y avoir une meilleure réponse.

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