NSString的drawInRect方法怎么样获得文字的高度

szuzsq 2013-02-18 05:27:21

NSString* str = @"hello kitty, would you tell me why do you want to go to shanghai?";

//这一句,我要怎么才能知道上面文字分行之后的确切高度,而不是给定一个固定值200?
[str drawInRect:NSMakeRect(10, 20, 100, 200) withAttributes:nil];

[str release];
...全文
92 4 点赞 打赏 收藏 举报
写回复
4 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
szuzsq 2013-02-19
引用 1 楼 Xiaolongyi 的回复:
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode; 此方法可以计算出文字放到一个固定的(constrainedToSize)大小里面的宽高; 比如你的:CGSize strSize = [st……
因为我是在OS X下,而不是iOS下.有些不同 以下代码,绘出来的是

	NSString *labelString = @"hello kitty, would you tell me why do you want to go to shanghai? 真心伤不起\n\
	楞个圾有圾和在有了上国有和国因为相关爆发正常情况下,计算行高只需要ascent+descent+leading即可。\n\
	在这个略有不同的情况下,leading的值会出现偏差,导致算出来的结果是错误的。如果不管行距,\n\
	ascent+descent计算出来的Glyph的高度还是正确的。这样就有了第一步在创建用于绘图的CFAttributedStringRef时,\n\
	除了设置字体,多设置一个CTParagraphStyleRef,其中特别应该确定行距kCTParagraphStyleSpecifierLineSpacing。\n\
	在计算这里时,先逐行计算ascent+descent,累加起来,再加上一个行数*之前设置好的行距,这样算出来的就是这些文本的实\n\
	际高度,CTLineGetTypographicBounds返回的结果是宽度,这样就可得到文本实际填充面积的Rect了";
	
    NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
								[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSRegularControlSize]], NSFontAttributeName,
								//[NSColor redColor], NSForegroundColorAttributeName,
								//[NSColor yellowColor], NSBackgroundColorAttributeName,
								nil];
	
    NSSize labelSize = [labelString sizeWithAttributes:attributes];
    NSRect labelRect = NSMakeRect(0, 0, labelSize.width, labelSize.height);
    [labelString drawInRect:labelRect withAttributes:attributes];
/////////////////////////// hello kitty, would you tell me why do you want to go to shanghai? 真心伤不起 楞个圾有圾和在有了上国有和国因为相关爆发正常情况下,计算行高只需要ascent+descent+leading即可。 在这个略有不同的情况下,leading的值会出现偏差,导致算出来的结果是错误的。如果不管行距, ascent+descent计算出来的Glyph的高度还是正确的。这样就有了第一步在创建用于绘图的CFAttributedStringRef时, 除了设置字体,多设置一个CTParagraphStyleRef,其中特别应该确定行距kCTParagraphStyleSpecifierLineSpacing。 在计算这里时,先逐行计算ascent+descent,累加起来,再加上一个行数*之前设置好的行距,这样算出来的就是这些文本的实 际高度,CTLineGetTypographicBounds返回的结果是宽度,这样就可得到文本实际填充面积的Rect了 ////////////////////////// 没有在200处分行,实事上我需要分行,效果如下,怎么实现呢? /////////////////////// hello kitty, would you tell me why do you want to go to shanghai? 真心伤不起 楞个圾有圾和在有了上国有和国因为相关 爆发正常情况下,计算行高只需要ascent+ descent+leading即可。 在这个略有不同的情况下,leading的值会 出现偏差,导致算出来的结果是错误的。如果不 管行距, ascent+descent计算出来的Glyph的高度 还是正确的。这样就有了第一步在创建用于绘图 的CFAttributedStringRef时, 除了设置字体,多设置一个 CTParagraphStyleRef,其中特别应该确定行距 kCTParagraphStyleSpecifierLineSpacing。 在计算这里时,先逐行计算ascent+ descent,累加起来,再加上一个行数*之前设置 好的行距,这样算出来的就是这些文本的实 际高度, CTLineGetTypographicBounds返回的结果是宽 度,这样就可得到文本实际填充面积的Rect了
  • 打赏
  • 举报
回复
szuzsq 2013-02-19

//以下代码没有正确计算出文字的高度...大家看看哪里出错了? 
 
- (int)getAttributedStringHeightWithString:(NSAttributedString*)string WidthValue:(int)width { 
    int h = 10000; //[string length] * 40; 
     
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)string); //string为要计算高度的NSAttributedString 
    CGMutablePathRef path = CGPathCreateMutable(); 
    CGPathAddRect(path, NULL, CGRectMake(0, 0, width, h)); //这里的高要设置足够大 
    CTFrameRef textFrame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL); 
    CGPathRelease(path); 
    CFRelease(framesetter); 
     
    NSArray* linesArray = (NSArray*)CTFrameGetLines(textFrame); 
    NSUInteger count = [linesArray count]; 
    if(count <= 0) { 
        CFRelease(textFrame); 
        return 0; 
    } 
    CGPoint origins[count]; 
    CTFrameGetLineOrigins(textFrame, CFRangeMake(0, 0), origins); 
    CGFloat line_y = origins[count - 1].y; //最后一行line的原点y坐标 
     
    CGFloat ascent, descent, leading; 
    CTLineRef line = (CTLineRef)[linesArray objectAtIndex: [linesArray count] - 1]; 
    CTLineGetTypographicBounds(line, &ascent, &descent, &leading); 
    CGFloat total_height = h - line_y + ascent + descent + leading + 1; //+1为了纠正descent转换成int小数点后舍去的值 
     
    CFRelease(textFrame); 
    return total_height; 
} 
 
- (void)drawRect:(NSRect)dirtyRect { 
    NSString* str = @"hello kitty, would you tell me why do you want to go to shanghai? 真心伤不起\n\ 
    楞个圾有圾和在有了上国有和国因为相关爆发\n正常情况下,计算行高只需要ascent+descent+leading即可。\n\ 
    在这个略有不同的情况下,leading的值会出现偏差,导致算出来的结果是错误的。如果不管行距,\n\ 
    ascent+descent计算出来的Glyph的高度还是正确的。这样就有了第一步在创建用于绘图的CFAttributedStringRef时,\n\ 
    除了设置字体,多设置一个CTParagraphStyleRef,其中特别应该确定行距kCTParagraphStyleSpecifierLineSpacing。\n\ 
    在计算这里时,先逐行计算ascent+descent,累加起来,再加上一个行数*之前设置好的行距,这样算出来的就是这些文本的实\n\ 
    际高度,CTLineGetTypographicBounds返回的结果是宽度,这样就可得到文本实际填充面积的Rect了"; 
 
    NSAttributedString* string = [[NSAttributedString alloc] initWithString:str]; 
    int h = [self getAttributedStringHeightWithString:string WidthValue:200]; 
    [str drawInRect:NSMakeRect(0, 0, 200, h) withAttributes:nil]; 
     
    [string release]; 
    [str release]; 
}
  • 打赏
  • 举报
回复
szuzsq 2013-02-19
在网上找了一段文字,没看懂........ /////////////////////////////////////////// Core Text提供了一系列方便的函数,可以很容易的把文本绘制在屏幕上,对于一个Frame来说,一般并不需要担心文本的排列问题,这些Core Text的函数都可以直接搞定,只要给他一个大小合适的CGRect就可以。 但,在某些情况下,我们还希望知道这段文本在绘制之后,对应绘制的字体字号设置,在屏幕上实际占用了多大面积。举例来说,有文本段落a,屏幕大小 rect,通常做法是以rect创建path,然后创建CTFramesetter,再然后创建CTFrame,最后用CTFrameDraw画出来,这 时候,往往文本段落占用的实际面积会小于rect,这时候就有必要获得这段文本所占用的真正面积。 最理想的情况是使用 double CTLineGetTypographicBounds( CTLineRef line, CGFloat* ascent, CGFloat* descent, CGFloat* leading ); 这是Core Text提供的函数,传入CTLine,就会得到这一行的ascent,descent和leading,在OSX上通常可以工作的很好,但是在 iOS(iPhone/iPad)上这个函数的结果略有不同。 正常情况下,计算行高只需要ascent+descent+leading即可。在这个略有不同的情况下,leading的值会出现偏差,导致算出 来的结果是错误的。如果不管行距,ascent+descent计算出来的Glyph的高度还是正确的。 这样就有了第一步 在创建用于绘图的CFAttributedStringRef时,除了设置字体,多设置一个CTParagraphStyleRef,其中特别应该 确定行距kCTParagraphStyleSpecifierLineSpacing。在计算这里时,先逐行计算ascent+descent,累加起 来,再加上一个行数*之前设置好的行距,这样算出来的就是这些文本的实际高度,CTLineGetTypographicBounds返回的结果是宽度, 这样就可得到文本实际填充面积的Rect了。 但是这还是有问题,因为OSX上和iOS处理不同,所以事实上iOS的模拟器和真机的最终效果是不一样的,这样调试程序很麻烦。 于是还需要第二步 在最终往页面上绘制的时候,不再用CTFrameDraw来一次绘制全部,而是使用CTLineDraw逐行画,在画之前,先用 CGContextSetTextPosition来设置好每行文本的位置。这样就保证了在任何平台上绘制效果一致。 问题就解决了。 CoreText在OS X和iOS上实现有很多细节区别,比如说,对CTRun的划分方式也不一样,在iOS上划分出来的Run数量比OSX上少很多,是按照字体划分的Run, 按照文档出来,这是正确的,但OSX上是一个字一个Run这样划分的,和文档不符。iOS上的处理显然效率更好。 stackoverflow 上有一个类 似的讨论,不过没考虑到iOS的区别
  • 打赏
  • 举报
回复
胡_码农 2013-02-19
- (CGSize)sizeWithFont:(UIFont *)font constrainedToSize:(CGSize)size lineBreakMode:(NSLineBreakMode)lineBreakMode; 此方法可以计算出文字放到一个固定的(constrainedToSize)大小里面的宽高; 比如你的:CGSize strSize = [str sizeWithFont:[UIFont systemFontOfSize:16] constrainedToSize:CGSizeMake(100, CGFLOAT_MAX) lineBreakMode:UILineBreakModeCharacterWrap];
  • 打赏
  • 举报
回复
相关推荐
发帖
iOS
加入

2.8w+

社区成员

主要讨论与iOS相关的软件和技术
申请成为版主
帖子事件
创建了帖子
2013-02-18 05:27
社区公告
暂无公告