Подтвердить что ты не робот

Есть ли "правильный" способ, чтобы NSTextFieldCell рисовал вертикально центрированный текст?

У меня есть NSTableView с несколькими текстовыми столбцами. По умолчанию dataCell для этих столбцов является экземпляром класса Apple NSTextFieldCell, который выполняет всевозможные замечательные вещи, но он рисует текст, выровненный с верхней частью ячейки, и я хочу, чтобы текст был вертикально центрирован в ячейка.

В NSTextFieldCell есть внутренний флаг, который можно использовать для вертикального центрирования текста, и он прекрасно работает. Однако, поскольку это внутренний флаг, его использование не санкционировано Apple, и оно может просто исчезнуть без предупреждения в будущей версии. В настоящее время я использую этот внутренний флаг, потому что он прост и эффективен. Apple, очевидно, потратила некоторое время на реализацию этой функции, поэтому мне не нравится идея ее повторного внедрения.

Итак, мой вопрос таков: Каков правильный способ реализовать то, что ведет себя точно так же, как Apple NStextFieldCell, но рисует вертикально центрированный текст вместо выровненного по верхнему краю?

Для записи здесь мое текущее "решение":

@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

Используется следующим образом:

[[myTableColumn dataCell] setVerticalCentering:YES];
4b9b3361

Ответ 1

Другие ответы не работали для нескольких строк. Поэтому я изначально продолжал использовать недокументированное свойство cFlags.vCentered, но это вызвало отклонение моего приложения из магазина приложений. Я закончил использовать модифицированную версию решения Matt Bell, которая работает для нескольких строк, переноса слов и усеченной последней строки:

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

(Этот код предполагает ARC; добавляет авторекламу после attrString.mutableCopy, если вы используете ручное управление памятью)

Ответ 2

Переопределение NSCell -titleRectForBounds: должно это сделать - это метод, ответственный за указание ячейке, где нужно нарисовать ее текст:

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

Ответ 3

FYI, это хорошо работает, хотя мне не удалось заставить его оставаться центрированным, когда вы редактируете ячейку... У меня иногда есть ячейки с большим количеством текста, и этот код может привести к их смещению, если текст высота больше, чем ячейка, в которой она пытается вертикально центрировать ее. Здесь мой модифицированный метод:

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

Для тех, кто пытается это использовать с помощью метода Matt Ball drawInteriorWithFrame:inView:, это больше не будет рисовать фон, если вы установили ячейку для ее рисования. Чтобы решить эту проблему, добавьте что-то вдоль линий

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

в начало вашего метода drawInteriorWithFrame:inView:.

Ответ 5

Хотя это довольно старый вопрос...

Я считаю, что стиль по умолчанию для реализации NSTableView предназначен исключительно для однострочного текстового отображения со всеми одинаковыми размерами и шрифтом.

В этом случае я рекомендую

  • Установить шрифт.
  • Отрегулируйте rowHeight.

Возможно, вы получите тихие плотные ряды. Затем добавьте их, установив intercellSpacing.

Например,

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

Здесь вы получите две настройки свойств.

enter image description here

Это не будет работать для многострочного текста, но очень хорош для быстрого вертикального центра, если вам не нужна поддержка нескольких строк.

Ответ 6

У меня была та же проблема, и вот решение, которое я сделал:

1) В Interface Builder выберите свой NSTableCellView. Удостоверьтесь, что он имеет размер как высота строки в Инспекторе размеров. Например, если высота строки равна 32, сделайте высоту ячейки 32

2) Убедитесь, что ваша ячейка хорошо помещена в вашу строку (я имею в виду видимый)

3) Выберите свой TextField внутри своей ячейки и перейдите к своему инспектору размера

4) Вы должны увидеть пункт "Упорядочить" и выбрать "Центр по вертикали в контейнере"

- > TextField будет центрировать себя в ячейке

Ответ 7

Нет. Правильный способ заключается в том, чтобы поместить поле в другое представление и использовать автомасштабирование или макет родительского представления, чтобы поместить его.