Есть ли “правильный” способ заставить NSTextFieldCell рисовать текст по вертикали?
-
22-07-2019 - |
Вопрос
У меня есть NSTableView
с несколькими текстовыми столбцами.По умолчанию, dataCell
для этих столбцов является экземпляром Apple NSTextFieldCell
класс, который делает всевозможные замечательные вещи, но он рисует текст, выровненный по верхней части ячейки, а я хочу, чтобы текст был вертикально центрирован в ячейке.
Существует внутренний флаг в NSTextFieldCell
это можно использовать для вертикального центрирования текста, и это прекрасно работает.Однако, поскольку это внутренний флаг, его использование не санкционировано Apple, и он может просто исчезнуть без предупреждения в будущей версии.В настоящее время я использую этот внутренний флаг, потому что он прост и эффективен.Apple, очевидно, потратила некоторое время на внедрение этой функции, поэтому мне не нравится идея ее повторного внедрения.
Итак;мой вопрос заключается в следующем: Каков правильный способ реализовать что-то, что ведет себя точно так же, как NSTextFieldCell от Apple, но отображает текст по вертикали, а не по верхнему краю?
Для протокола, вот мое текущее "решение":
@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];
Решение
Другие ответы не сработали для нескольких строк.Поэтому я изначально продолжал использовать недокументированный cFlags.vCentered
свойство, но это привело к тому, что мое приложение было отклонено из App Store.В итоге я использовал модифицированную версию решения Мэтта Белла, которая работает с несколькими строками, переносом слов и усеченной последней строкой:
-(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];
}
К вашему сведению, это работает хорошо, хотя мне не удалось заставить его оставаться центрированным при редактировании ячейки...Иногда у меня есть ячейки с большим объемом текста, и этот код может привести к их смещению, если высота текста больше, чем у ячейки, в которой он пытается расположить его по вертикали.Вот мой модифицированный метод:
- (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;
}
Для всех, кто пытается это сделать, используя Matt Ball drawInteriorWithFrame:inView:
метод, при этом больше не будет рисоваться фон, если вы настроили свою ячейку на рисование фона.Чтобы решить эту проблему, добавьте что-то вроде
[[NSColor lightGrayColor] set];
NSRectFill(cellFrame);
к началу вашего drawInteriorWithFrame:inView:
способ.
Хотя это довольно старый вопрос...
Я полагаю, что стиль реализации NSTableView по умолчанию предназначен строго для отображения однострочного текста с одинаковым размером и шрифтом.
В таком случае, я рекомендую,
- Установите шрифт.
- Отрегулируйте
rowHeight
.
Может быть, у вас тихо получатся плотные ряды.А затем дополните их, установив intercellSpacing
.
Например,
core_table_view.rowHeight = [NSFont systemFontSizeForControlSize:(NSSmallControlSize)] + 4;
core_table_view.intercellSpacing = CGSizeMake(10, 80);
Вот что вы получите с двумя настройками свойств.
Это не сработает для многострочного текста, но вполне достаточно для быстрого вертикального центрирования, если вам не нужна поддержка многострочности.
У меня была такая же проблема, и вот решение, которое я нашел :
1) В Interface Builder выберите свой NSTableCellView.Убедитесь, что он равен высоте строки в инспекторе размеров.Например, если ваша высота строки равна 32, сделайте высоту ячейки 32
2) Убедитесь, что ваша ячейка хорошо расположена в вашей строке (я имею в виду видимую).
3) Выберите нужное текстовое поле внутри ячейки и перейдите в инспектор размеров
4) Вы должны увидеть элемент "Упорядочить" и выбрать "Центрировать по вертикали в контейнере".
--> Текстовое поле будет располагаться по центру ячейки
Нет.Правильный способ - поместить поле в другой вид и использовать автоматическую разметку или макет этого родительского вида для его позиционирования.