it-swarm.com.de

Gibt es eine "richtige" Möglichkeit, NSTextFieldCell vertikal zentrierten Text zeichnen zu lassen?

Ich habe eine NSTableView mit mehreren Textspalten. Standardmäßig ist die dataCell für diese Spalten eine Instanz der NSTextFieldCell-Klasse von Apple, die alle Arten von wunderbaren Dingen ausführt, aber Text am oberen Rand der Zelle ausrichtet, und der Text soll vertikal in der Zelle zentriert sein.

In NSTextFieldCell gibt es ein internes Flag, mit dem der Text vertikal zentriert werden kann, und das funktioniert hervorragend. Da es sich jedoch um ein internes Flag handelt, wird die Verwendung von Apple nicht gebilligt und es könnte in einer zukünftigen Version einfach ohne Vorwarnung verschwinden. Ich verwende derzeit diese interne Flagge, weil sie einfach und effektiv ist. Apple hat offensichtlich einige Zeit damit verbracht, die Funktion zu implementieren, daher mag ich die Idee, sie erneut zu implementieren, nicht.

So; Meine Frage lautet: Was ist der richtige Weg, um etwas zu implementieren, das sich genau wie Apples NStextFieldCell verhält, aber vertikal zentrierten Text anstelle von oben ausrichtet?

Für die Aufzeichnung ist hier meine gegenwärtige "Lösung":

@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

Wird wie folgt verwendet:

[[myTableColumn dataCell] setVerticalCentering:YES];
49
e.James

Die anderen Antworten funktionierten nicht für mehrere Zeilen. Daher verwendete ich zunächst die undokumentierte cFlags.vCentered-Eigenschaft, was jedoch dazu führte, dass meine App vom App Store abgelehnt wurde. Am Ende habe ich eine modifizierte Version von Matt Bells Lösung verwendet, die für mehrere Zeilen, Zeilenumbruch und eine abgeschnittene letzte Zeile funktioniert:

-(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;
}

(Dieser Code setzt ARC voraus; fügen Sie nach attrString.mutableCopy eine Autorelease hinzu, wenn Sie die manuelle Speicherverwaltung verwenden.)

35
Jakob Egger

Das Überschreiben von -titleRectForBounds: von NSCell sollte dies tun - dies ist die Methode, die der Zelle mitteilt, wo der Text gezeichnet werden soll:

- (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];
}
30
Matt Ball

Zu Ihrer Information, das funktioniert gut, auch wenn ich es nicht geschafft habe, es beim Bearbeiten der Zelle zentriert zu halten ... Ich habe manchmal Zellen mit großen Textmengen, und dieser Code kann dazu führen, dass sie falsch ausgerichtet werden, wenn die Texthöhe größer ist dann versucht die Zelle, sie vertikal zu zentrieren. Hier ist meine modifizierte Methode:

- (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;
}
4
coradine

Für jeden, der dies mit der drawInteriorWithFrame:inView:-Methode von Matt Ball versucht, wird dadurch kein Hintergrund mehr gezeichnet, wenn Sie Ihre Zelle so einstellen, dass ein solcher gezeichnet wird. Um dies zu lösen, fügen Sie etwas in der Richtung von hinzu

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

an den Anfang Ihrer drawInteriorWithFrame:inView:-Methode.

4
Greg Sexton

Obwohl dies eine ziemlich alte Frage ist ...

Ich glaube, der Standardstil der NSTableView-Implementierung ist ausschließlich für die Anzeige von einzeiligem Text mit der gleichen Größe und Schriftart gedacht. 

In diesem Fall empfehle ich,

  1. Schriftart einstellen.
  2. rowHeight anpassen.

Vielleicht werden Sie ruhig dichte Reihen bekommen. Geben Sie ihnen dann eine Auffüllung, indem Sie intercellSpacing einstellen. 

Zum Beispiel, 

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

Hier erhalten Sie mit zwei Immobilienanpassungen.

enter image description here

Dies funktioniert nicht für mehrzeiligen Text, aber sehr gut für eine schnelle vertikale Mitte, wenn Sie keine mehrzeilige Unterstützung benötigen.

2
Eonil

Ich hatte das gleiche Problem und hier ist die Lösung, die ich gemacht habe: 

1) Wählen Sie im Interface Builder Ihre NSTableCellView aus. Stellen Sie sicher, dass die Größe im Zeileninspektor der Zeilenhöhe entspricht. Wenn Ihre Zeilenhöhe beispielsweise 32 ist, stellen Sie die Zellenhöhe 32 ein 

2) Stellen Sie sicher, dass Ihre Zelle gut in Ihrer Zeile platziert ist (ich meine sichtbar)

3) Wählen Sie Ihr TextField in Ihrer Zelle aus und gehen Sie zu Ihrem Größeninspektor

4) Sie sollten den Eintrag "Anordnen" sehen und "Vertikal in Container zentrieren" auswählen.

-> Das Textfeld wird sich in der Zelle zentrieren

1
AllezLesBleus

Nein. Der richtige Weg ist, das Feld in eine andere Ansicht zu setzen und das automatische Layout oder das Layout dieser übergeordneten Ansicht zu positionieren.

0
Frank Krueger