浅析CoreText自由绘制(3)

http://blog.csdn.net/xcysuccess3 版权所有 ,转载请说明

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上的处理显然效率更好。


分栏绘制:

- (void)drawRect:(CGRect)rect {
    NSString *longText = @"Lorem ipsum dolor sit amet, "; /* ... */
    NSMutableAttributedString *string = [[NSMutableAttributedString alloc]   initWithString:longText];
    // make a few words bold
    CTFontRef helvetica = CTFontCreateWithName(CFSTR("Helvetica"), 14.0, NULL);
    CTFontRef helveticaBold = CTFontCreateWithName(CFSTR("Helvetica-Bold"), 14.0, NULL);
    [string addAttribute:(id)kCTFontAttributeName   value:(id)helvetica   range:NSMakeRange(0, [string length])];
    [string addAttribute:(id)kCTFontAttributeName   value:(id)helveticaBold   range:NSMakeRange(6, 5)];
    [string addAttribute:(id)kCTFontAttributeName    value:(id)helveticaBold   range:NSMakeRange(109, 9)];
    [string addAttribute:(id)kCTFontAttributeName   value:(id)helveticaBold   range:NSMakeRange(223, 6)];
    // add some color
    [string addAttribute:(id)kCTForegroundColorAttributeName    value:(id)[UIColor redColor].CGColor   range:NSMakeRange(18, 3)];
    [string addAttribute:(id)kCTForegroundColorAttributeName   value:(id)[UIColor greenColor].CGColor   range:NSMakeRange(657, 6)];
    [string addAttribute:(id)kCTForegroundColorAttributeName   value:(id)[UIColor blueColor].CGColor   range:NSMakeRange(153, 6)];
    // layout master
    CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(   (CFAttributedStringRef)string);
    // left column form
    CGMutablePathRef leftColumnPath = CGPathCreateMutable();
    CGPathAddRect(leftColumnPath, NULL,   CGRectMake(0, 0,    self.bounds.size.width/2.0,    self.bounds.size.height));
    // left column frame
    CTFrameRef leftFrame = CTFramesetterCreateFrame(framesetter,   CFRangeMake(0, 0),    leftColumnPath, NULL);
    // right column form
    CGMutablePathRef 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(leftFrame).length;
    // right column frame
    CTFrameRef rightFrame = 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(leftFrame, context);
    CTFrameDraw(rightFrame, context);
    // cleanup
    CFRelease(leftFrame);
    CGPathRelease(leftColumnPath);
    CFRelease(rightFrame);
    CGPathRelease(rightColumnPath);
    CFRelease(framesetter);
    CFRelease(helvetica);
    CFRelease(helveticaBold);
    [string release];
}
http://dingxiuwei666.blog.163.com/blog/static/1615705220117310519287/

起点随笔

    2012-10-22

    ios交流QQ群:237305299


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值