我有一个自定义UIView,它通过CoreText绘制NSString:
- (NSMutableAttributedString *)getAttributedString : (NSString *)displayText {
string = [[NSMutableAttributedString alloc]
initWithString:displayText];
helvetica = CTFontCreateWithName(CFSTR("Helvetica"), 20.0, NULL);
[string addAttribute:(id)kCTFontAttributeName
value:(__bridge id)helvetica
range:NSMakeRange(0, [string length])];
return string;
}
- (void)drawRect:(CGRect)rect
{
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(
(__bridge CFAttributedStringRef)string);
// left column form
leftColumnPath = CGPathCreateMutable();
CGPathAddRect(leftColumnPath, NULL,
CGRectMake(0, 0,
self.bounds.size.width,
self.bounds.size.height));
// left column frame
textleftFrame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, 0),
leftColumnPath, NULL);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
// right column form
rightColumnPath = CGPathCreateMutable();
CGPathAddRect(rightColumnPath, NULL,
CGRectMake(self.bounds.size.width/2.0, 0,
self.bounds.size.width/2.0,
self.bounds.size.height));
NSInteger rightColumStart = CTFrameGetVisibleStringRange(textleftFrame).length;
// right column frame
textrightFrame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(rightColumStart, 0),
rightColumnPath,
NULL);
}
// flip the coordinate system
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);
// draw
CTFrameDraw(textleftFrame, context);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
CTFrameDraw(textrightFrame, context);
}
// cleanup
CFRelease(textleftFrame);
CGPathRelease(leftColumnPath);
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
CFRelease(textrightFrame);
CGPathRelease(rightColumnPath);
}
CFRelease(framesetter);
CFRelease(helvetica);
CFRelease(helveticaBold);
}
然后,在另一个类中,我尝试使用boundingRectWithSize来计算 View 显示文本的时间(然后我将UIScrollView设置为与此匹配):
NSMutableAttributedString * attributedString = [textView getAttributedString:text];
// Code here for iOS 7.0 - sizeWithFont is deprecated.
CGRect textBoxSize = [attributedString boundingRectWithSize:CGSizeMake(315.f, CGFLOAT_MAX) options: (NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading) context:nil];
textView.frame = CGRectMake(textView.frame.origin.x, pictureSpace, textBoxSize.size.width, textBoxSize.size.height);
上面的getAttributedString方法。问题是textView的高度略短,因此切断了so这样的文本的最后一行。谁能说出什么错了?
另外,顺便说一句,为什么boundingRectWithSize的大小必须为315(即比屏幕宽度稍短)而不是320才能正常工作?在320处,textView最终变得略宽于屏幕。
编辑-这似乎只在某些字体下才发生-例如Verdana可以正常工作。更懂行的人知道这是否与字形有关吗?
谢谢 !
最佳答案
在MMProgressHud项目中,使用boundingRectWithSize:options:context:
方法计算了不同组件的不同大小,使用HelveticaNeue-Light
字体遇到了一些问题,但是使用Verdana
字体却没有人遇到问题。
我在NSString上创建了一个新类别,以使用Core-Text进行常规测量以制定自己的测量方法。这受此post和此post的启发。
#import "NSString+CustomMetrics.h"
#import<CoreText/CoreText.h>
@implementation NSString (CustomMetrics)
- (CGSize) boundingRectWithSize:(CGSize) bounds andFont:(UIFont*) uiFont
{
CTFontRef ctFont = CTFontCreateWithName((CFStringRef) uiFont.fontName,uiFont.pointSize, NULL);
CGFloat ascent = CTFontGetAscent(ctFont);
CGFloat descent = CTFontGetDescent(ctFont);
CGFloat leading = CTFontGetLeading(ctFont);
if (leading < 0)
leading = 0;
leading = floor (leading + 0.5);
CGFloat lineHeight = floor (ascent + 0.5) + floor (descent + 0.5) + leading;
CGFloat ascenderDelta = 0;
if (leading > 0)
ascenderDelta = 0;
else
ascenderDelta = floor (0.2 * lineHeight + 0.5);
CGFloat defaultLineHeight = lineHeight + ascenderDelta;
CTParagraphStyleSetting paragraphSettings[1] = { {kCTParagraphStyleSpecifierLineSpacingAdjustment, sizeof (CGFloat), &defaultLineHeight} };
CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphSettings, 1);
CFRange textRange = CFRangeMake(0, self.length);
// Create an empty mutable string big enough to hold our test
CFMutableAttributedStringRef string = CFAttributedStringCreateMutable(kCFAllocatorDefault, self.length);
// Inject our text into it
CFAttributedStringReplaceString(string, CFRangeMake(0, 0), (CFStringRef) self);
// Apply our font and line spacing attributes over the span
CFAttributedStringSetAttribute(string, textRange, kCTFontAttributeName, ctFont);
CFAttributedStringSetAttribute(string, textRange, kCTParagraphStyleAttributeName, paragraphStyle);
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(string);
CFRange fitRange;
CGSize frameSize = CTFramesetterSuggestFrameSizeWithConstraints(framesetter, textRange, NULL, bounds, &fitRange);
CFRelease(framesetter);
CFRelease(string);
CFRelease(ctFont);
return frameSize;
}
@end