美文网首页iOS 富文本iOS富文本
关于CoreText,自己做一些小纪录

关于CoreText,自己做一些小纪录

作者: 罴又罴 | 来源:发表于2016-12-02 15:08 被阅读89次

        首先我是萌新,ios开发新手,一些大牛觉得不对,错误的,请勿喷我怎么吃螃蟹,请告诉我怎么吃就好了,谢谢了。

        之前因为项目需求,要给小说阅读器中内容加上下划线,但是这个下划线又跟其他的不一样,这个下划线要在基线的位置再靠上一些,当初不明白为什么要这么做,而且效果也很难看,用户体验也不好,但是老大说这能防止pdf扫描vip章节内容,所以还是得老老实实的做,就对coreText开始了研究。

    本次主要用到的点在与CTLineRef.接下来先对其做一些了解。

    1.字符(Character)和字形(Glyphs)

    排版系统中文本显示的一个重要的过程就是字符到字形的转换,字符是信息本身的元素,而字形是字符的图形表征,字符还会有其它表征比如发音。 字符在计算机中其实就是一个编码,某个字符集中的编码,比如Unicode字符集,就囊括了大都数存在的字符。 而字形则是图形,一般都存储在字体文件中,字形也有它的编码,也就是它在字体中的索引。 一个字符可以对应多个字形(不同的字体,或者同种字体的不同样式:粗体斜体等);多个字符也可能对应一个字形,比如字符的连写( Ligatures)。

    下面就来看看字形的各个参数也就是所谓的字形度量Glyph Metrics,其实我认为就是一个小时侯学写字母的时候的作业本一样的各个线

    bounding box(边界框 bbox),这是一个假想的框子,它尽可能紧密的装入字形。

    baseline(基线),一条假想的线,一行上的字形都以此线作为上下位置的参考,在这条线的左侧存在一个点叫做基线的原点,

    ascent(上行高度)从原点到字体中最高(这里的高深都是以基线为参照线的)的字形的顶部的距离,ascent是一个正值

    descent(下行高度)从原点到字体中最深的字形底部的距离,descent是一个负值(比如一个字体原点到最深的字形的底部的距离为2,那么descent就为-2)

    linegap(行距),linegap也可以称作leading(其实准确点讲应该叫做External leading),行高lineHeight则可以通过 ascent + |descent| + linegap 来计算。

    一些Metrics专业知识还可以参考Free Type的文档 Glyph metrics,其实iOS就是使用Free Type库来进行字体渲染的。

    以上图片和部分概念来自苹果文档 Querying Font Metrics ,Text Layout

    2.坐标系

    苹果编程中的坐标系不明白为什么会各有不同。 传统的Mac中的坐标系的原点在左下角,比如NSView默认的坐标系,原点就在左下角。但Mac中有些View为了其实现的便捷将原点变换到左上角,像NSTableView的坐标系坐标原点就在左上角。iOS UIKit的UIView的坐标系原点在左上角。

    看完上边儿这些,该上代码勒。

    先拿一个定义好的属性字符串。

    NSMutableAttributedString *attrString = [[NSMutableAttributedString  alloc] initWithString:self.text];//这个self.text 就是你要用到的字符串

    [attrString setAttributes:self.coreTextAttributes range:NSMakeRange(0, attrString.length)];//这里的self.coreTextAttributes就是一个字典,来配置这个属性字符串的,可在他的set方法中随意设置,比如颜色,下划线,删除线,字型等等

    然后把属性字符串放到frame中

    CTFramesetterRef frameSetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef) attrString);

    CGPathRef path = CGPathCreateWithRect(self.bounds, NULL);

    if (_ctFrame != NULL) {  //这里的_ctFrame 就是一个装有字符属性的集合

    CFRelease(_ctFrame), _ctFrame = NULL;

    }

    _ctFrame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, 0), path, NULL);

    CFRelease(path);

    CFRelease(frameSetter);

    做完了上面这些,就该开始画字了。

    在- (void)drawRect:(CGRect)rect方法中

    if (!_ctFrame) return;

    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetTextMatrix(context, CGAffineTransformIdentity);

    CTFrameDraw(_ctFrame, context);

    这样写的效果如图

    是镜像过来的,要再翻过来

    CGAffineTransform transform = CGAffineTransformMake(1,0,0,-1,0,self.bounds.size.height);

    CGContextConcatCTM(context, transform);

    加上以上这两句就可以了,就顺利的将字画到了画布上。

    再之后给文字加个方框

    CGMutablePathRef path = CGPathCreateMutable();

    CGPathAddRect(path, NULL, CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height));

    CFArrayRef lines = CTFrameGetLines(_ctFrame);

    CFIndex linecount = CFArrayGetCount(lines);

    CGPoint origins[linecount];

    CTFrameGetLineOrigins(_ctFrame, CFRangeMake(0, 0), origins);

    NSInteger lineIndex = 0;

    for (id oneLine in (__bridge NSArray *)lines) {

    CGRect lineBounds = CTLineGetImageBounds((CTLineRef)oneLine, context);

    lineBounds.origin.x += origins[lineIndex].x;

    lineBounds.origin.y += origins[lineIndex].y;

    lineIndex ++;

    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);

    CGContextSetLineWidth(context, 1.0);

    CGPoint poins[] = {CGPointMake(lineBounds.origin.x, lineBounds.origin.y),CGPointMake(lineBounds.origin.x+lineBounds.size.width, lineBounds.origin.y),CGPointMake(lineBounds.origin.x+lineBounds.size.width, lineBounds.origin.y+lineBounds.size.height),CGPointMake(lineBounds.origin.x, lineBounds.origin.y+lineBounds.size.height)};//绘制四边,位置随意调整,位置可以调整之后也就可以实现我的下划线在任何位置了

    CGContextAddLines(context, poins, 4);

    CGContextClosePath(context);

    CGContextStrokePath(context);

    }

    }

    其中主要是取CTFrameRef集合中的CTLines ,在其中他包含了字符的各种属性,rang等

    第一次写文章,主要是当时搞这个东西走了弯路,对coreText的不了解,也在csdn和cocoachina上问了好多人,都没解决,防止以后忘记,自己再纪录一下。

    我目前做的项目是做的小说阅读器,网上的素材真的是不多,现在也算是写的差不多了,但是在预加载,内存缓存和磁盘缓存上做的还是不行,希望有做阅读器这方面有好的方案的,希望可以教教小弟,第一篇小文 也就搞定勒。

    相关文章

      网友评论

        本文标题:关于CoreText,自己做一些小纪录

        本文链接:https://www.haomeiwen.com/subject/vvhjjttx.html