CoreText入门

简介

CoreText是用于处理文字和字体的底层技术。它直接和Core Graphics(又被称为Quartz)打交道。Quartz是一个2D图形渲染引擎,能够处理OSX和iOS中的图形显示问题。

UIWebView也常用于处理复杂的排版,对应排版他们之间的优劣如下(摘自 《iOS开发进阶》—— 唐巧):

  • CoreText占用的内容更少,渲染速度更快。UIWebView占用的内存多,渲染速度慢。
  • CoreText在渲染界面的前就可以精确地获得显示内容的高度(只要有了CTFrame即可),而WebView只有渲染出内容后,才能获得内容的高度(而且还需要用JavaScript代码来获取)。
  • CoreText的CTFrame可以在后台线程渲染,UIWebView的内容只能在主线程(UI线程)渲染。
  • 基于CoreText可以做更好的原生交互效果,交互效果可以更加细腻。而UIWebView的交互效果都是用JavaScript来实现的,在交互效果上会有一些卡顿的情况存在。例如,在UIWebView下,一个简单的按钮按下的操作,都无法做出原生按钮的即时和细腻的按下效果。

CoreText排版的劣势:

  • CoreText渲染出来的内容不能像UIWebView那样方便地支持内容的复制。
  • 基于CoreText来排版需要自己处理很多复制的逻辑,例如需要自己处理图片与文字混排相关的逻辑,也需要自己实现连接点击操作的支持。

Core Text对象模型

CoreText入门_第1张图片
CoreText入门_第2张图片

  • framesetter framesetter对应的类型是 CTFramesetter,通过CFAttributedString进行初始化,它作为CTFrame对象的生产工厂,负责根据path生产对应的CTFrame
  • CTFrame CTFrame是可以通过CTFrameDraw函数直接绘制到context上的,当然你可以在绘制之前,操作CTFrame中的CTLine,进行一些参数的微调
  • CTLine 可以看做Core Text绘制中的一行的对象 通过它可以获得当前行的line ascent,line descent ,line leading,还可以获得Line下的所有Glyph Runs
  • CTRun 或者叫做 Glyph Run,是一组共享想相同attributes(属性)的字形的集合体

上面说了这么多对也没一个东西和图片绘制有关系,其实吧,Core Text本身并不支持图片绘制,图片的绘制你还得通过Core Graphics来进行。只是Core Text可以通过CTRun的设置为你的图片在文本绘制的过程中留出适当的空间。这个设置就使用到CTRunDelegate了,看这个名字大概就可以知道什么意思了,CTRunDelegate作为CTRun相关属性或操作扩展的一个入口,使得我们可以对CTRun做一些自定义的行为。为图片留位置的方法就是加入一个空白的CTRun,自定义其ascent,descent,width等参数,使得绘制文本的时候留下空白位置给相应的图片。然后图片在相应的空白位置上使用Core Graphics接口进行绘制。
使用CTRunDelegateCreate可以创建一个CTRunDelegate,它接收两个参数,一个是callbacks结构体,一个是所有callback调用的时候需要传入的对象。 callbacks的结构体为CTRunDelegateCallbacks,主要是包含一些回调函数,比如有返回当前run的ascent,descent,width这些值的回调函数,至于函数中如何鉴别当前是哪个run,可以在CTRunDelegateCreate的第二个参数来达到目的,因为CTRunDelegateCreate的第二个参数会作为每一个回调调用时的入参。

例子

- (void)drawRect:(CGRect)rect { [super drawRect:rect]; //得到当前绘制画布的上下文,用于后续将内容绘制在画布上 CGContextRef context = UIGraphicsGetCurrentContext(); //将坐标系上下翻转 CGContextSetTextMatrix(context, CGAffineTransformIdentity); CGContextTranslateCTM(context, 0, self.bounds.size.height); CGContextScaleCTM(context, 1.0, -1.0); //创建绘制区域 CGMutablePathRef path = CGPathCreateMutable(); CGPathAddRect(path, NULL, self.bounds); NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"Hello World!"]; CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attString); CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, [attString length]), path, NULL); CTFrameDraw(frame, context); CFRelease(frame); CFRelease(path); CFRelease(framesetter); }

CoreText入门_第3张图片

改变创建区域的代码如下:

    CGMutablePathRef path = CGPathCreateMutable();
    CGPathAddEllipseInRect(path, NULL, self.bounds);

    NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"Hello World! Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!"];

CoreText入门_第4张图片

参考文档

  • Core Text 入门
  • 使用CoreText实现图文混排
  • iOS文字排版(CoreText)那些事
  • 如何使用 CoreText 创建一个简单的杂志应用

你可能感兴趣的:(CoreText入门)