I am attempting to measure an NSAttributedString
's height given a constant width using the following method:
-(CGFloat)calculateHeightForAttributedString:(NSAttributedString*)attributedNotes {
CGFloat scrollerWidth = [NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy];
CGFloat width = self.tableView.frame.size.width - self.cellNotesWidthConstraint - scrollerWidth;
// http://www.cocoabuilder.com/archive/cocoa/54083-height-of-string-with-fixed-width-and-given-font.html
NSTextView *tv = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, width - 20, 1e7)];
tv.font = [NSFont userFontOfSize:32];
[tv.textStorage setAttributedString:attributedNotes];
[self setScaleFactor:[self convertSliderValueToFontScale:self.fontScaleSlider] forTextView:tv];
[tv.layoutManager glyphRangeForTextContainer:tv.textContainer];
[tv.layoutManager ensureLayoutForTextContainer:tv.textContainer];
return [tv.layoutManager usedRectForTextContainer:tv.textContainer].size.height + 10.0f; // add a little bit of a buffer
}
Basically, the width is the table view's size minus the scroller and a little bit of each cell that is used to display other information. This method works really well as long as the text scale (via convertSliderValueToFontScale:
) is 1.0. The result from usedRectForTextContainer
is incorrect if I change the scale factor, however -- as if the scale factor was not being accounted for.
The scale is set in setScaleFactor:forTextView:
on the NSTextView as follows (scalar is the actual scale amount):
[textView scaleUnitSquareToSize:NSMakeSize(scaler, scaler)];
Any ideas on how to fix this?
Edit: I've got a sample project to try here: Github. Strangely enough, things work if the scale is < 0, and they randomly seem to work in the 4.XXX range on occasion...
The answer turns out to be simple: add the NSTextView
as a subview of an NSClipView
with the same frame as the NSTextView
.
The final height function is as follows:
-(CGFloat)calculateHeightForAttributedString:(NSAttributedString*)attributedNotes {
CGFloat width = self.textView.frame.size.width;
// http://www.cocoabuilder.com/archive/cocoa/54083-height-of-string-with-fixed-width-and-given-font.html
NSTextView *tv = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, width, 1e7)];
tv.horizontallyResizable = NO;
tv.font = [NSFont userFontOfSize:32];
tv.alignment = NSTextAlignmentLeft;
[tv.textStorage setAttributedString:attributedNotes];
[self setScaleFactor:self.slider.floatValue forTextView:tv];
// In order for usedRectForTextContainer: to be accurate with a scale, you MUST
// set the NSTextView as a subview of an NSClipView!
NSClipView *clipView = [[NSClipView alloc] initWithFrame:NSMakeRect(0, 0, width, 1e7)];
[clipView addSubview:tv];
[tv.layoutManager glyphRangeForTextContainer:tv.textContainer];
[tv.layoutManager ensureLayoutForTextContainer:tv.textContainer];
return [tv.layoutManager usedRectForTextContainer:tv.textContainer].size.height;
}