CoreText应用之代码详细篇

2019-08-08  本文已影响0人  LiuffSunny

如何使用CoreText

CoreText是需要自己处理绘制,不像UILabel等最上层的控件 ,所以我们必须在drawRect中绘制,为了更好地使用,我们需要自定义一个UIView。
CoreText绘图流程:先创建一个framesetter——>创建path——>创建frame(携带framesetter和path等信息)——>生成上下文context——>CTFrameDraw绘制frame——>释放
转换坐标系

UIKit的坐标系原点是在右上角,CoreText的坐标原点是在左下角,并且绘制的内容是颠倒的,所以需要进行坐标转换,绘制的内容显示才能正常

781681-20160107095453075-2053394561.png.jpg
#pragma mark - drawRect
- (void)drawRect:(CGRect)rect
{
    // 1.获取图形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 2.翻转坐标系
    CGAffineTransform transform = CGAffineTransformScale(CGAffineTransformMakeTranslation(0, rect.size.height), 1.f, -1.f);
    CGContextConcatCTM(context, transform);
    
    // 3.获取CTFrameRef
    self.frameRef = [self.attributedString prepareFrameRefWithRect:rect];
    
    // 4.绘制高亮背景颜色
    [self drawHighlightedColor];
    
    // 5.一行一行的绘制文字
    [self frameLineDraw];
    
    // 6.绘制图片
    [self drawImages];
}

一.关于上下文

由于绘制都是在Context上下文上进行的,所以先补充一些上下文的知识,上下文是什么?为什么要有上下文?上下文是怎么工作的?
Context上下文
上下文是什么:
上下文定义了我们需要绘制的地方。
为什么要有上下文:
要盛水,就需要有容器;要画画,就需要画板。上下文就是一个画板,在英语中词根con和com都有很多一起的意思,再看Context,就是很多文本在一起,这就是上下文了。
上下文是怎么工作的:
UIKit维护着一个上下文堆栈,UIKit 方法总是绘制到最顶层的上下文中。你可以使用 UIGraphicsGetCurrentContext() 来得到最顶层的上下文。你可以使用 UIGraphicsPushContext()和UIGraphicsPopContext()在 UIKit 的堆栈中推进或取出上下文。最为突出的是,UIKit 使用 UIGraphicsBeginImageContextWithOptions() 和 UIGraphicsEndImageContext()方便的创建类似于 CGBitmapContextCreate()的位图上下文。混合调用 UIKit 和 Core Graphics 非常简单:

二.主要函数

1、传入CTFrame,返回一个装有多个CTLine对象的数组。

CFArrayRef CTFrameGetLines( CTFrameRef frame ) CT_AVAILABLE(10_5, 3_2);

2、获取数组中的元素个数

CFIndex CFArrayGetCount(CFArrayRef theArray);

3、获取数组中第idx个元素

const void *CFArrayGetValueAtIndex(CFArrayRef theArray, CFIndex idx);

4、 获取所有CTLineRef的基础原点,传入CTFrame,CFRange,和一个CGPoint的结构体数组指针,该函数会把每一个CTLine的origin坐标写到数组里。

void CTFrameGetLineOrigins( CTFrameRef frame, CFRange range, CGPoint origins[] ) CT_AVAILABLE(10_5, 3_2);

5、获取CTLine中文字在整段文字中的Range

CFRange CTLineGetStringRange( CTLineRef line ) CT_AVAILABLE(10_5, 3_2);

6、获取CTLine中的CTRun的数组

CFArrayRef CTLineGetGlyphRuns( CTLineRef line ) CT_AVAILABLE(10_5, 3_2);

7、获取CTRun在整段文字中的Range

CFRange CTRunGetStringRange( CTRunRef run ) CT_AVAILABLE(10_5, 3_2);

8、 获取点击处position文字在整段文字中的index

CFIndex CTLineGetStringIndexForPosition( CTLineRef line, CGPoint position ) CT_AVAILABLE(10_5, 3_2);

9、获取整段文字中charIndex位置的字符相对line的原点的x值

CGFloat CTLineGetOffsetForStringIndex( CTLineRef line, CFIndex charIndex, CGFloat * __nullable secondaryOffset ) CT_AVAILABLE(10_5, 3_2);

10、获取数组中字形个个数

CFIndex CTLineGetGlyphCount( CTLineRef line ) CT_AVAILABLE(10_5, 3_2);

11、设置CoreText绘制前的坐标。设置基线位置

CG_EXTERN void CGContextSetTextPosition(CGContextRef __nullable c, CGFloat x, CGFloat y) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

12、绘制CTLine。

void CTLineDraw( CTLineRef line, CGContextRef context ) CT_AVAILABLE(10_5, 3_2);

13、获取CTLine的上行高度,下行高度,行距

double CTLineGetTypographicBounds( CTLineRef line, CGFloat * __nullable ascent, CGFloat * __nullable descent, CGFloat * __nullable leading ) CT_AVAILABLE(10_5, 3_2);

14、设置当前文本矩阵

CG_EXTERN void CGContextSetTextMatrix(CGContextRef __nullable c, CGAffineTransform t) CG_AVAILABLE_STARTING(__MAC_10_0, __IPHONE_2_0);

15、获取一行文字的范围, 就是指把这一行文字点有的像素矩阵作为一个image图片,来得到整个矩形区域。相对于每一行基线原点的偏移量和宽高(例如:{{1.2, -2.57227}, {208.025, 19.2523}},就是相对于本身的基线原点向右偏移1.2个单位,向下偏移2.57227个单位,后面是宽高)

CGRect CTLineGetImageBounds( CTLineRef line, CGContextRef __nullable context ) CT_AVAILABLE(10_5, 3_2);

从绘制路径CGMutablePathRef开始

void CGPathAddRect(CGMutablePathRef path, const CGAffineTransform *m, CGRect rect);
//*m是一个指向仿射变换矩阵的指针,如果不需要可以设置为NULL,如果指定了矩阵,Core Graphics将转换应用于矩形,然后将其添加到路径中。
//rect就是需要将该矩阵添加到哪里。
/**
 * 根据传入的宽高来获取CTFrameRef
 */
- (CTFrameRef)prepareFrameRefWithRect:(CGRect)rect
                       framesetterRef:(CTFramesetterRef)framesetterRef
{
//CGMutablePathRef是一个可变的路径,可通过CGPathCreateMutable()创建,该路径在被创建后,需要加到Context中。

//CGPathAddRect就是将上面的路径添加到上下文中的方法。
    // 创建路径 
    CGMutablePathRef path = CGPathCreateMutable();
    // 添加路径
    CGPathAddRect(path, NULL, rect);
    
    // 获取frameRef
    // CFRangeMake(0,0) 表示绘制全部文字
    CTFrameRef frameRef = CTFramesetterCreateFrame(framesetterRef, CFRangeMake(0, 0), path, NULL);
    
    // 释放内存
    CFRelease(path);
    
    return frameRef;
}

上一篇下一篇

猜你喜欢

热点阅读