How to properly determine width of an attributed string
What I want to do: layout text using NSLayoutManager and set its NSTextContainer to the width of the widest string (glyph-wise) in an array of strings.
What my problem is: The methods for determining the total 'glyph-width' seem to be incorrect because when I render the text it wraps.
I did an experiment using a 32 character string with the Monaco 12 point font and the length is reported as 224.0, but the text will only stop wrapping if the length is set to 234.0.
This code demonstrates what I said above and shows a vertical line on the right of the computed glyph-width.
- (void)drawRect:(NSRect)rect {
NSRect bounds = [self bounds];
[[NSColor whiteColor] drawS开发者_运维知识库watchInRect: 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;
}
Have you accounted for the text container's -lineFragmentPadding?
Have you taken a look at this category for NSString and NSAttributedString NS(Attributed)String+Geometrics?
If it's not exactly what you're looking for you could perhaps see some of what they are doing to calculate the size.
精彩评论