CoreText是专门进行文字绘制的函数集合
CoreText 将单个字符分为
· baseline(基线),一条假想的线,一行上的字形都以此线作为上下位置的参考,在这条线的左侧存在一个点叫做基线的原点,
· ascent(上行高度)从原点到字体中最高(这里的高深都是以基线为参照线的)的字形的顶部的距离,ascent是一个正值
· descent(下行高度)从原点到字体中最深的字形底部的距离,descent是一个负值(比如一个字体原点到最深的字形的底部的距离为2,那么descent就为-2)
· linegap(行距),linegap也可以称作leading(其实准确点讲应该叫做External leading),行高lineHeight则可以通过 ascent + |descent| + linegap 来计算。
使用CoreText绘制一段文字的步骤为:
1.获取画布 CGContextRef
2.设置坐标系。因为CoreText的坐标系是左下角,但是UIView的坐标系是左上角,需要进行相应翻转,才方便进行操作。
CGContextSetTextMatrix(context,CGAffineTransformIdentity);//设置字形变换矩阵,当前值表示不做任何字形变换处理
CGContextTranslateCTM(context, 0, self.frame.size.height);//将绘制原点从左下角位移到左上角
CGContextScaleCTM(context, 1, -1);//将坐标翻转180度
3.设置需要绘制的文本 NSMutableAttributedString
4.使用CTFramesetterCreateWithAttributedString 从NSMutableAttributedString中生成 CTFramesetterRef
5.设置CTFrameRef的绘制区域
CGMutablePathRef path=CGPathCreateMutable();
CGPathAddRect(path, NULL, CGRectMake(20, 20, self.frame.size.width-40, self.frame.size.height-40));
6.从CTFramesetterRef中生成 CTFrameRef 。
CTFramesetterCreateFrame(ctframesetter, CFRangeMake(0, attrstr.length), path, NULL);
7.绘制CTFrameRef
CTFrameDraw(ctframe, context);
除了直接绘制CTFrameRef之外还可以对每一行进行单独处理,步骤为:
其他步骤跟上面前6步骤完全一样
7.获取CTFrameRef中的所有行
CFArrayRef array=CTFrameGetLines(ctframe); //获取所有的行的数组
NSInteger arrcount=CFArrayGetCount(array);//获取数组的长度
8.循环这个行数组获取行对象
CTLineRef line=CFArrayGetValueAtIndex(array, i);//获取第i行
9.可以使用 CTLineCreateJustifiedLine 函数对行进行处理,将所有不满一行的进行拉伸到满一行的位置
CTLineRef justifiedLine = CTLineCreateJustifiedLine(line, 1.0f, self.frame.size.width-40);
CFRelease(line);
line = justifiedLine;
10.可以动态调整行的位置
float asent;//行的上半部分高度
float descent;//行的下半部分高度
float leading;//行间距
CTLineGetTypographicBounds(line, &asent, &descent, &leading);//获取行的一些属性
CGContextSetTextPosition(context,myline.point.x,self.frame.size.height-(asent+descent+leading)*(i+1)-20);//设置行的文字位置,行的坐标位置设置仍然以左下角为原点的
11.将行文字绘制在界面上
CTLineDraw(line, context);
这里面有一些函数需要特殊注意,可能比较有用途
1.这个函数用来处理行宽不一致的问题,有些行的由于内部有一些标点符号,无法占满整行,导致行宽参差不齐,这个函数专门处理这个问题。
CTLineRef __nullable CTLineCreateJustifiedLine(
CTLineRef line,
CGFloat justificationFactor,
double justificationWidth ) CT_AVAILABLE(10_5, 3_2);
2. 获取行中间某一个索引位置的字符的x坐标
其中 charIndex参数的索引是整段文字的文字位置索引
CGFloat CTLineGetOffsetForStringIndex(
CTLineRef line,
CFIndex charIndex,
CGFloat * __nullable secondaryOffset ) CT_AVAILABLE(10_5, 3_2);
3.根据一个点的坐标位置获取在这个行中字符位置的索引
CFIndex CTLineGetStringIndexForPosition(
CTLineRef line,
CGPoint position ) CT_AVAILABLE(10_5, 3_2);
4.获取行的一些信息,其中返回值为行的整体宽度,行的高度为ascent+descent
double CTLineGetTypographicBounds(
CTLineRef line,
CGFloat * __nullable ascent,
CGFloat * __nullable descent,
CGFloat * __nullable leading ) CT_AVAILABLE(10_5, 3_2);