Как вы обводите _outside_ NSAttributedString? - PullRequest
13 голосов
/ 17 декабря 2010

Я использовал NSStrokeWidthAttributeName на NSAttributedString объектах, чтобы нарисовать контур вокруг текста.Проблема в том, что обводка находится внутри области заполнения текста.Когда текст небольшой (например, толщиной 1 пиксель), штриховка затрудняет чтение текста.Что я действительно хочу, так это инсульт снаружи.Есть ли способ сделать это?

Я пробовал NSShadow без смещения и размытия, но он слишком размытый и трудно увидетьЕсли бы был способ увеличить размер тени без размытия, это тоже сработало бы.

1 Ответ

33 голосов
/ 17 декабря 2010

Хотя могут быть и другие способы, один из способов сделать это состоит в том, чтобы сначала нарисовать строку только штрихом, а затем нарисовать строку только с заливкой, прямо поверх того, что было нарисовано ранее. (Adobe InDesign на самом деле имеет эту встроенную функцию, в которой, как представляется, применяется только штрих к внешней стороне буквы, что помогает с удобочитаемостью).

Это просто примерное представление, показывающее, как этого добиться (вдохновлено http://developer.apple.com/library/mac/#qa/qa2008/qa1531.html):

Сначала настройте атрибуты:

@implementation MDInDesignTextView

static NSMutableDictionary *regularAttributes = nil;
static NSMutableDictionary *indesignBackgroundAttributes = nil;
static NSMutableDictionary *indesignForegroundAttributes = nil;

- (void)drawRect:(NSRect)frame {
    NSString *string = @"Got stroke?";
    if (regularAttributes == nil) {
        regularAttributes = [[NSMutableDictionary
    dictionaryWithObjectsAndKeys:
        [NSFont systemFontOfSize:64.0],NSFontAttributeName,
        [NSColor whiteColor],NSForegroundColorAttributeName,
        [NSNumber numberWithFloat:-5.0],NSStrokeWidthAttributeName,
        [NSColor blackColor],NSStrokeColorAttributeName, nil] retain];
    }

    if (indesignBackgroundAttributes == nil) {
        indesignBackgroundAttributes = [[NSMutableDictionary
        dictionaryWithObjectsAndKeys:
        [NSFont systemFontOfSize:64.0],NSFontAttributeName,
        [NSNumber numberWithFloat:-5.0],NSStrokeWidthAttributeName,
        [NSColor blackColor],NSStrokeColorAttributeName, nil] retain];
    }

    if (indesignForegroundAttributes == nil) {
        indesignForegroundAttributes = [[NSMutableDictionary
        dictionaryWithObjectsAndKeys:
        [NSFont systemFontOfSize:64.0],NSFontAttributeName,
        [NSColor whiteColor],NSForegroundColorAttributeName, nil] retain];
    }

    [[NSColor grayColor] set];
    [NSBezierPath fillRect:frame];

    // draw top string
    [string drawAtPoint:
        NSMakePoint(frame.origin.x + 200.0, frame.origin.y + 200.0)
        withAttributes:regularAttributes];

    // draw bottom string in two passes
    [string drawAtPoint:
        NSMakePoint(frame.origin.x + 200.0, frame.origin.y + 140.0)
        withAttributes:indesignBackgroundAttributes];
    [string drawAtPoint:
        NSMakePoint(frame.origin.x + 200.0, frame.origin.y + 140.0)
        withAttributes:indesignForegroundAttributes];
}

@end

Это дает следующий вывод:

alt text

alt text

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

Если производительность является проблемой, вы всегда можете посмотреть на более низкий уровень, такой как CoreGraphics или CoreText.

...