Измерьте высоту строки в какао - PullRequest
1 голос
/ 20 января 2012

Я искал процедуру для строки измерения высоты и нашел ее в другом вопросе о переполнении стека. И это отлично работает для моих NSTableViewColumns, которые имеют перенос слов в виде разрывов строк У меня вопрос: что, если я вместо этого переверну разрыв строки на перенос символов, как я могу обновить этот код?

- (NSSize)sizeForWidth:(float)width 
                height:(float)height {
    NSSize answer = NSZeroSize ;
     gNSStringGeometricsTypesetterBehavior =   NSTypesetterBehavior_10_2_WithCompatibility;
    if ([self length] > 0) {
        // Checking for empty string is necessary since Layout Manager will give the nominal
        // height of one line if length is 0.  Our API specifies 0.0 for an empty string.
        NSSize size = NSMakeSize(width, height) ;
        NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:size] ;
        NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:self] ;
        NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init] ;
        [layoutManager addTextContainer:textContainer] ;
        [textStorage addLayoutManager:layoutManager] ;
        [layoutManager setHyphenationFactor:0.0] ;
        if (gNSStringGeometricsTypesetterBehavior != NSTypesetterLatestBehavior) {
            [layoutManager setTypesetterBehavior:gNSStringGeometricsTypesetterBehavior] ;
        }
        // NSLayoutManager is lazy, so we need the following kludge to force layout:
        [layoutManager glyphRangeForTextContainer:textContainer] ;

        answer = [layoutManager usedRectForTextContainer:textContainer].size ;
        [textStorage release] ;
        [textContainer release] ;
        [layoutManager release] ;

        // In case we changed it above, set typesetterBehavior back
        // to the default value.
        gNSStringGeometricsTypesetterBehavior = NSTypesetterLatestBehavior ;
    }

    return answer ;
}

1 Ответ

2 голосов
/ 21 января 2012

Такое ощущение, что вы заново изобретаете [NSAttributedString boundingRectWithSize:options:] (или просто size).Я что-то упустил в вашей реализации?NSLayoutManager предназначен для размещения быстро меняющихся строк (например, в текстовом представлении).Большую часть времени это излишне.Вы намеренно обойдете его оптимизацию (в своей строке вы заметили, что NSLayoutManager ленивый, что вы подразумеваете под оптимизированным: D)

В любом случае, чтобы изменить поведение обертывания, вам нужно изменить NSAttributedString сам.Обтекание является частью стиля абзаца .Примерно так (не проверено; может не скомпилироваться):

// Lazy here. I'm assuming the entire string has the same style
NSMutableParagraphStyle *style = [[self attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL] mutableCopy]; 
[style setLineBreakMode:NSLineBreakByCharWrapping];
NSAttributedString *charWrappedString = [self mutableCopy];
[charWrappedString setAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, [self length]];

NSRect boundingRect = [self boundingRectWithSize:NSMakeSize(width, height) options:0];
NSSize size = boundRect.size;

[style release];
[charWrappedString release];

return size;

Стили немного сложнее, потому что они включают в себя несколько вещей, но вы должны установить их все вместе.Поэтому, если в атрибутивной строке были разные стили, вам нужно перебрать строку, обрабатывая каждый effectiveRange.(Вы хотите прочитать документы, чтобы понять компромисс между attributesAtIndex:effectiveRange: и attributesAtIndex:longestEffectiveRange:inRange:.)

...