Есть ли "правильный" способ, чтобы 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];
Ответы
Ответ 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
Нет. Правильный способ заключается в том, чтобы поместить поле в другое представление и использовать автомасштабирование или макет родительского представления, чтобы поместить его.