Есть ли "правильный" способ заставить 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];
7 ответов
Другие ответы не работают для нескольких строк. Поэтому я изначально продолжал использовать недокументированные 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, если вы используете ручное управление памятью)
Переопределение NSCell's -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];
}
Для тех, кто пытается это с помощью Мэтта Болла drawInteriorWithFrame:inView:
метод, это больше не будет рисовать фон, если вы установили свою ячейку, чтобы нарисовать один. Чтобы решить эту проблему, добавьте что-то вроде
[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);
в начале вашего drawInteriorWithFrame:inView:
метод.
К вашему сведению, это работает хорошо, хотя мне не удалось заставить его оставаться в центре, когда вы редактируете ячейку... У меня иногда есть ячейки с большим количеством текста, и этот код может привести к их смещению, если высота текста больше затем ячейка, в которой он пытается центрировать его по вертикали. Вот мой модифицированный метод:
- (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;
}
Нет. Правильный способ - поместить поле в другое представление и использовать автоматическое расположение или расположение этого родительского представления для его размещения.
Хотя это довольно старый вопрос...
Я считаю, что стиль реализации NSTableView по умолчанию предназначен исключительно для однострочного отображения текста с одинаковым размером и шрифтом.
В этом случае я рекомендую,
- Установить шрифт
- регулировать
rowHeight
,
Может быть, вы получите тихие плотные ряды. А затем, дать им отступы, установив intercellSpacing
,
Например,
core_table_view.rowHeight = [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4;
core_table_view.intercellSpacing = CGSizeMake(10, 80);
Вот что вы получите с двумя настройками свойства.
Это не будет работать для многострочного текста, но достаточно хорошо для быстрого вертикального центра, если вам не нужна многострочная поддержка.
У меня была та же проблема, и вот решение, которое я сделал:
1) В Интерфейсном Разработчике выберите свой NSTableCellView. Убедитесь, что он такой же большой, как высота строки в Инспекторе размеров. Например, если ваша высота строки 32, сделайте вашу высоту ячейки 32
2) Убедитесь, что ваша клетка хорошо расположена в вашем ряду (я имею в виду видимый)
3) Выберите ваш TextField внутри вашей ячейки и перейдите к инспектору размера
4) Вы должны увидеть пункт "Упорядочить" и выбрать "Центрировать по вертикали в контейнере".
-> TextField будет центрироваться в ячейке