Есть ли «правильный» способ заставить NSTextFieldCell рисовать вертикально центрированный текст?

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

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

Так; мой вопрос такой:What is the right way to implement something that behaves exactly like Apple's NStextFieldCell, but draws vertically centered text instead of top-aligned?

Для справки, вот мое текущее «решение»:

@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];
 e.James10 мар. 2013 г., 18:57
@KeithSmiley: спасибо за хедз-ап!
 Jack06 янв. 2013 г., 07:27
Вы должны принять ответ Якоба Эггера. Когда используется код из принятого ответа, это вызывает странный сбой, когдаNSTextFieldCell отредактировано. Ответ Якоба решает проблему.
 Jakob Egger24 окт. 2011 г., 23:52
Я не думаю, что блок try / catch в этом случае имеет какой-либо смысл, поскольку _cflags - это структура C, а не объект Objective C. Если эта структура будет изменена в будущей версии Mac OS X, могут произойти всевозможные странные вещи, но не будет выдано никаких исключений.
 Keith Smiley09 мар. 2013 г., 19:35
У меня было отклонено приложение от MAS для использования_cFlags.vCentered, Вы были предупреждены.
 e.James25 окт. 2011 г., 00:45
@Jakob Egger: Вы, вероятно, правы. Я нашел это решение в Интернете и скопировал его как есть.

Ответы на вопрос(7)

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

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

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

-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];
}
 e.James06 авг. 2009 г., 17:19
Красиво сделано. Это работает как шарм!
 25 авг. 2011 г., 15:41
Это действительно также с NSTextFieldCell внутри NSTextField? Это не похоже на работу.edit 2009? Может быть, он немного староват. :)
 e.James06 авг. 2009 г., 08:47
Это кажется многообещающей идеей, но она не работает для меня. Я создал подклассNSTextFieldCellскопировал ваш код и использовал пользовательский класс для ячеек в моемNSTableView, ноtitleRectForBounds метод никогда не вызывается.
 06 авг. 2009 г., 12:13
Ах, я забыл, что NSTextFieldCell в основном лежит в его документации - вы правы, по умолчанию NSTextFieldCell не использует -titleRectForBounds :. Я обновил свой ответ для переопределения -drawInteriorWithFrame: inView: чтобы нарисовать текст в нужном месте.
 03 авг. 2012 г., 05:08
@MattBall Если текст в NSTextField выделен, он снова выравнивается по верху.

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

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

Set font. Adjust rowHeight.

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

Например,

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

Вот что вы получите с двумя настройками свойства.

enter image description here

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

 e.James01 дек. 2014 г., 20:35
Это разумное решение для однострочных ячеек, которое, вероятно, охватывает большинство случаев использования. Спасибо!

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

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

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

4) Вы должны увидеть & quot; Arrange & quot; и выберите & quot; Центрировать по вертикали в контейнере & quot;

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

Решение Вопроса

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

-(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, если вы используете ручное управление памятью)

 06 янв. 2013 г., 20:23
Кстати, можно ли отцентрировать текст при редактировании? мойNSTextFieldCell имеет длину в несколько строк, и, когда пользователь дважды щелкает текст для его редактирования, он возвращается к началу, пока редактирование не будет завершено.
 20 мая 2014 г., 08:59
Есть ли способ перецентрировать / перерисовать текст во время записи в поле?
 08 янв. 2013 г., 09:58
Мое приложение может только просматривать данные, поэтому эта проблема не возникла у меня. Тем не менее, я считаю, что вам придется предоставить свой собственный редактор полей и сделать некоторые хитрые вещи, чтобы перестроить редактор полей по мере ввода пользователем. УвидетьWorking With the Field Editor в документах Apple.
 06 янв. 2013 г., 07:25
Это работает очень хорошо. Принятый ответ вызвал странный сбой при редактировании ячейки.
 22 мая 2012 г., 06:24
Это сработало для меня, и это очень хорошая реализация - спасибо.

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

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

чтобы поместить поле в другое представление и использовать автоматическое расположение или расположение этого родительского представления для его размещения.

 e.James01 дек. 2014 г., 20:34
Хорошо, но тогда как мне сделать так, чтобы Поле само меняло размер (изменял его высоту) в соответствии с текстом? Без этого у меня будет хорошо отцентрированное текстовое поле, но текст внутри поля все равно будет выровнен по верхнему краю, поэтому текст будет отображаться над центром в родительском представлении.
 05 нояб. 2015 г., 08:45
Это абсолютно правильный ответ. Разрешить NSTextField полагаться на свой собственный размер (отрегулируйте размер шрифта по своему усмотрению, который будет соответствовать изменению внутреннего размера), затем добавьте его в качестве подпредставления в представление контейнера, которое будет обрамлять его относительно того, что содержит текстовое поле и это обрамляет внутренний размер текстового поля по отношению к общему пространству.
 01 мар. 2016 г., 18:02
@ Asher, на самом деле нет, изменение размера шрифта не приводит к изменению размера поля:dropbox.com/s/9b4vgcp7kuujll2/…
 27 сент. 2016 г., 21:57
Звучит так, что автопоставка не настроена должным образом.

Ваш ответ на вопрос