Existe-t-il un & # 8220; droit & # 8221; moyen pour que NSTextFieldCell dessine un texte centré verticalement?

StackOverflow https://stackoverflow.com/questions/1235219

Question

J'ai un NSTableView avec plusieurs colonnes de texte. Par défaut, le dataCell de ces colonnes est une instance de la classe NSTextFieldCell d’Apple, qui fait toutes sortes de choses merveilleuses, mais elle dessine un texte aligné avec le haut de la cellule, et je veux que le texte soit centré verticalement dans la cellule.

Il existe un indicateur interne dans NSTextFieldCell qui peut être utilisé pour centrer le texte verticalement, et cela fonctionne à merveille. Cependant, comme il s'agit d'un drapeau interne, son utilisation n'est pas autorisée par Apple et il pourrait tout simplement disparaître sans avertissement dans une prochaine version. J'utilise actuellement ce drapeau interne parce qu'il est simple et efficace. Apple a évidemment passé un certain temps à implémenter cette fonctionnalité, je n’aime donc pas l’idée de la ré-implémenter.

Alors; Ma question est la suivante: Quelle est la bonne façon de mettre en œuvre un système qui se comporte exactement comme le NStextFieldCell d’Apple, mais dessine un texte centré verticalement au lieu d’être aligné au sommet?

Pour mémoire, voici ma "solution" actuelle:

@interface NSTextFieldCell (MyCategories)
- (void)setVerticalCentering:(BOOL)centerVertical;
@end

@implementation NSTextFieldCell (MyCategories)
- (void)setVerticalCentering:(BOOL)centerVertical
{
    @try { _cFlags.vCentered = centerVertical ? 1 : 0; }
    @catch(...) { NSLog(@"*** unable to set vertical centering"); }
}
@end

Utilisé comme suit:

[[myTableColumn dataCell] setVerticalCentering:YES];
Était-ce utile?

La solution

Les autres réponses ne fonctionnaient pas pour plusieurs lignes. Par conséquent, j'ai initialement continué à utiliser la propriété non documentée cFlags.vCentered , mais mon application a été rejetée de la boutique d'applications. J'ai fini par utiliser une version modifiée de la solution de Matt Bell qui fonctionne pour plusieurs lignes, le retour à la ligne et la dernière ligne tronquée:

-(void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
    NSAttributedString *attrString = self.attributedStringValue;

    /* if your values can be attributed strings, make them white when selected */
    if (self.isHighlighted && self.backgroundStyle==NSBackgroundStyleDark) {
        NSMutableAttributedString *whiteString = attrString.mutableCopy;
        [whiteString addAttribute: NSForegroundColorAttributeName
                            value: [NSColor whiteColor]
                            range: NSMakeRange(0, whiteString.length) ];
        attrString = whiteString;
    }

    [attrString drawWithRect: [self titleRectForBounds:cellFrame] 
                     options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin];
}

- (NSRect)titleRectForBounds:(NSRect)theRect {
    /* get the standard text content rectangle */
    NSRect titleFrame = [super titleRectForBounds:theRect];

    /* find out how big the rendered text will be */
    NSAttributedString *attrString = self.attributedStringValue;
    NSRect textRect = [attrString boundingRectWithSize: titleFrame.size
                                               options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin ];

    /* If the height of the rendered text is less then the available height,
     * we modify the titleRect to center the text vertically */
    if (textRect.size.height < titleFrame.size.height) {
        titleFrame.origin.y = theRect.origin.y + (theRect.size.height - textRect.size.height) / 2.0;
        titleFrame.size.height = textRect.size.height;
    }
    return titleFrame;
}

(Ce code suppose ARC; ajoutez une libération automatique après attrString.mutableCopy si vous utilisez la gestion manuelle de la mémoire)

Autres conseils

Remplacer le -titleRectForBounds: de NSCell doit le faire - c'est la méthode responsable pour indiquer à la cellule où dessiner son texte:

- (NSRect)titleRectForBounds:(NSRect)theRect {
    NSRect titleFrame = [super titleRectForBounds:theRect];
    NSSize titleSize = [[self attributedStringValue] size];
    titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height) / 2.0;
    return titleFrame;
}

- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
    NSRect titleRect = [self titleRectForBounds:cellFrame];
    [[self attributedStringValue] drawInRect:titleRect];
}

Pour votre information, cela fonctionne bien, même si je n’ai pas réussi à le garder centré lorsque vous modifiez la cellule ... j’ai parfois des cellules avec une grande quantité de texte et ce code peut entraîner leur désalignement si le texte hauteur est plus grande que la cellule dans laquelle il essaie de le centrer verticalement. Voici ma méthode modifiée:

- (NSRect)titleRectForBounds:(NSRect)theRect 
 {
    NSRect titleFrame = [super titleRectForBounds:theRect];
    NSSize titleSize = [[self attributedStringValue] size];
     // test to see if the text height is bigger then the cell, if it is,
     // don't try to center it or it will be pushed up out of the cell!
     if ( titleSize.height < theRect.size.height ) {
         titleFrame.origin.y = theRect.origin.y + (theRect.size.height - titleSize.height) / 2.0;
     }
    return titleFrame;
}

Toute personne utilisant cette méthode à l'aide de la méthode drawInteriorWithFrame: inView: de Matt Ball ne créera plus d'arrière-plan si vous avez défini votre cellule pour en dessiner un. Pour résoudre ce problème, ajoutez quelque chose dans le sens de

[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);

au début de votre méthode drawInteriorWithFrame: inView: .

Bien que ce soit une assez vieille question ...

Je pense que le style par défaut de l'implémentation NSTableView est strictement destiné à l'affichage de texte sur une seule ligne avec la même taille & amp; Police de caractère.

Dans ce cas, je recommande,

  1. Définir la police.
  2. Ajustez rowHeight .

Peut-être aurez-vous des rangées denses et silencieuses. Et ensuite, donnez-leur du padding en définissant intercellSpacing .

Par exemple,

    core_table_view.rowHeight               =   [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4;
    core_table_view.intercellSpacing        =   CGSizeMake(10, 80);

Voici ce que vous obtiendrez avec deux ajustements de propriétés.

entrer la description de l'image ici

Cela ne fonctionnera pas pour un texte multiligne, mais très bon pour un centre vertical rapide si vous n'avez pas besoin de la prise en charge multiligne.

J'ai eu le même problème et voici la solution que j'ai trouvée:

1) Dans Interface Builder, sélectionnez votre NSTableCellView. Assurez-vous qu'il soit aussi grand que la hauteur de la ligne dans l'inspecteur de taille. Par exemple, si votre hauteur de ligne est de 32, définissez votre hauteur de cellule 32

2) Assurez-vous que votre cellule est bien placée dans votre rangée (je veux dire visible)

3) Sélectionnez votre champ de texte dans votre cellule et accédez à votre inspecteur de taille

4) Vous devriez voir " Arranger " élément et sélectionnez "Centrer verticalement dans le conteneur"

- > Le TextField va se centrer dans la cellule

Non. La bonne façon consiste à placer le champ dans une autre vue et à utiliser la présentation automatique ou celle de cette vue parent pour le positionner.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top