How to correctly determine the width of an attribute string

What I want to do: layout text using NSLayoutManager and set its NSTextContainer to the width of the widest line (glyph-wise) in the string array.

What is my problem: the methods for determining the overall "glyph width" seem incorrect, because when I render the text that it wraps.

I conducted an experiment using a 32-character string with a Monaco 12 font, and the length is specified as 224.0, but the text will only stop when the length is set to 234.0.

This code demonstrates what I said above and shows a vertical line to the right of the calculated glyph width.

- (void)drawRect:(NSRect)rect {
    NSRect bounds = [self bounds];

    [[NSColor whiteColor] drawSwatchInRect: bounds];
    [[NSColor blackColor] setStroke];
    [[NSBezierPath bezierPathWithRect: bounds] stroke];

    NSMutableParagraphStyle *thisParagraphStyle = [[NSMutableParagraphStyle defaultParagraphStyle] mutableCopy];
    [thisParagraphStyle setLineBreakMode: NSLineBreakByCharWrapping];
    [thisParagraphStyle setAlignment: NSLeftTextAlignment];

    NSFont *fontUsed = [NSFont fontWithName: @"Monaco" size: 12];

    NSDictionary *glyphAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                     fontUsed, NSFontAttributeName,
                                     thisParagraphStyle, NSParagraphStyleAttributeName,
                                     [NSColor blackColor], NSForegroundColorAttributeName,
                                     NULL];

    NSTextStorage *textStorage = [[NSTextStorage alloc] initWithString:@"00112233445566778899001122334455\n00112233445566778899001122334455\n00112233445566778899001122334455\n00112233445566778899001122334455\n"];

    [textStorage setAttributes: glyphAttributes range:  NSMakeRange(0, [textStorage length])];

    NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];

    NSSize textContainerSize;
    textContainerSize.width = [@"00112233445566778899001122334455" sizeWithAttributes: glyphAttributes].width;
    textContainerSize.height = bounds.size.height;

    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize: textContainerSize];
    [layoutManager addTextContainer:textContainer];

    [textContainer release];
    [textStorage addLayoutManager:layoutManager];
    [layoutManager release];
    NSRange glyphRange = [layoutManager glyphRangeForTextContainer: textContainer];

    [layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: NSMakePoint(0.0 , 0.0)];
    [textStorage release];
    [thisParagraphStyle release];

    // Indicate right text boundary from computed width
    NSBezierPath *rightTextBoundary = [NSBezierPath bezierPath];
    [rightTextBoundary moveToPoint: NSMakePoint(textContainerSize.width, 0.0)];
    [rightTextBoundary lineToPoint: NSMakePoint(textContainerSize.width, bounds.size.height-1)];
    [rightTextBoundary stroke];

    NSLog(@"View width: %f", bounds.size.width);
    NSLog(@"Calculated width1: %f", textContainerSize.width);
    NSLog(@"Calculated width2: %f\n\n", [@"00112233445566778899001122334455" boundingRectWithSize: NSMakeSize(FLT_MAX, FLT_MAX)
                                                                         options: NSStringDrawingUsesDeviceMetrics
                                                                      attributes: glyphAttributes].size.width);
}

- (BOOL) isFlipped {
    return YES;
}
+3
2

NSString NSAttributedString NS (Attributed) String + Geometrics?

, , , , , .

+1

Source: https://habr.com/ru/post/1762394/


All Articles