博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
初识CoreText
阅读量:4509 次
发布时间:2019-06-08

本文共 6736 字,大约阅读时间需要 22 分钟。

一、基本知识介绍

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

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

Roman 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的文档 ,其实iOS就是使用库来进行字体渲染的。

2.坐标系

首先不得不说 苹果编程中的坐标系花样百出,经常让开发者措手不及。 传统的Mac中的坐标系的原点在左下角,比如NSView默认的坐标系,原点就在左下角。但Mac中有些View为了其实现的便捷将原点变换到左上角,像NSTableView的坐标系坐标原点就在左上角。iOS UIKit的UIView的坐标系原点在左上角。 

往底层看,Core Graphics的context使用的坐标系的原点是在左下角。而在iOS中的底层界面绘制就是通过Core Graphics进行的,那么坐标系列是如何变换的呢? 在UIView的drawRect方法中我们可以通过UIGraphicsGetCurrentContext()来获得当前的Graphics Context。drawRect方法在被调用前,这个Graphics Context被创建和配置好,你只管使用便是。如果你细心,通过CGContextGetCTM(CGContextRef c)可以看到其返回的值并不是CGAffineTransformIdentity,通过打印出来看到值为

Printing description of contextCTM:  (CGAffineTransform) contextCTM = {          a = 1          b = 0          c = 0          d = -1          tx = 0          ty = 460  }

 

这是非retina分辨率下的结果,如果是如果是retina上面的a,d,ty的值将会乘2,如果是iPhone 5,ty的值会再大些。 但是作用都是一样的就是将上下文空间坐标系进行了flip,使得原本左下角原点变到左上角,y轴正方向也变换成向下。

上面说了一大堆,下面进入正题,Core Text一开始便是定位于桌面的排版系统,使用了传统的原点在左下角的坐标系,所以它在绘制文本的时候都是参照左下角的原点进行绘制的。 但是iOS的UIView的drawRect方法的context被做了次flip,如果你啥也不做处理,直接在这个context上进行Core Text绘制,你会发现文字是镜像且上下颠倒。 如图所示

所以首先我们需要把坐标系翻转过来,插入一下代码即可

CGContextSetTextMatrix(context, CGAffineTransformIdentity);CGContextTranslateCTM(context, 0, self.bounds.size.height);CGContextScaleCTM(context, 1.0, -1.0);

接下来我们实现一个最基本最简单的绘制,代码如下

- (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);    // 创建绘制的字符串和CTFrame    NSAttributedString *attString = [[NSAttributedString alloc] initWithString:@"Hello core text 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);}

实现效果如图所示:

 

 这里来解释一下CTFramesetter和CTFrame,首先我们来看两张图,可以帮助我们更好的理解CoreText的对象模型

      

CTFrame可以理解为一个整体的画布由很多行(CTLine)组成,而每一行又由一个或者多个小方块(CTRun)组成,我们不需要自己创建CTRun,Core Text将根据NSAttributedString的属性来自动创建CTRun。每个CTRun对象对应不同的属性,正因此,你可以自由的控制字体、颜色、字间距等等信息。

CTFramesetter其实就是CTFrame的工厂方法,通过给定的NSAttributedString,生成CTRrame,同时系统自动的创建了CTTypesetter,CTTypesetter就是管理你的字体的类。

那么又如何来使用NSAttributedString呢?如何来设置行高,字体样式,大小呢?

下面列举了可以设置的属性

const CFStringRef kCTCharacterShapeAttributeName;              //字体形状属性  必须是CFNumberRef对象默认为0,非0则对应相应的字符形状定义,如1表示传统字符形状const CFStringRef kCTFontAttributeName;                        //字体属性   必须是CTFont对象const CFStringRef kCTKernAttributeName;                        //字符间隔属性 必须是CFNumberRef对象const CFStringRef kCTLigatureAttributeName;                 //设置是否使用连字属性,设置为0,表示不使用连字属性。标准的英文连字有FI,FL.默认值为1,既是使用标准连字。也就是当搜索到f时候,会把fl当成一个文字。必须是CFNumberRef 默认为1,可取0,1,2const CFStringRef kCTForegroundColorAttributeName;             //字体颜色属性  必须是CGColor对象,默认为blackconst CFStringRef kCTForegroundColorFromContextAttributeName;  //上下文的字体颜色属性 必须为CFBooleanRef 默认为False,const CFStringRef kCTParagraphStyleAttributeName;              //段落样式属性 必须是CTParagraphStyle对象 默认为NILconst CFStringRef kCTStrokeWidthAttributeName;              //笔画线条宽度 必须是CFNumberRef对象,默为0.0f,标准为3.0fconst CFStringRef kCTStrokeColorAttributeName;              //笔画的颜色属性 必须是CGColorRef 对象,默认为前景色const CFStringRef kCTSuperscriptAttributeName;              //设置字体的上下标属性 必须是CFNumberRef对象 默认为0,可为-1为下标,1为上标,需要字体支持才行。如排列组合的样式Cn1const CFStringRef kCTUnderlineColorAttributeName;           //字体下划线颜色属性 必须是CGColorRef对象,默认为前景色const CFStringRef kCTUnderlineStyleAttributeName;           //字体下划线样式属性 必须是CFNumberRef对象,默为kCTUnderlineStyleNone 可以通过CTUnderlineStypleModifiers 进行修改下划线风格const CFStringRef kCTVerticalFormsAttributeName;//文字的字形方向属性 必须是CFBooleanRef 默认为false,false表示水平方向,true表示竖直方向const CFStringRef kCTGlyphInfoAttributeName;//字体信息属性 必须是CTGlyphInfo对象const CFStringRef kCTRunDelegateAttributeName//CTRun 委托属性 必须是CTRunDelegate对象

举例来说明下吧

- (void)drawRect:(CGRect)rect {        [super drawRect:rect];        // 1.    CGContextRef context = UIGraphicsGetCurrentContext();        // 2.抓换坐标    CGContextSetTextMatrix(context, CGAffineTransformIdentity);    CGContextTranslateCTM(context, 0, self.bounds.size.height);    CGContextScaleCTM(context, 1.0, -1.0);        NSMutableAttributedString *attriString = [[NSMutableAttributedString alloc] initWithString:@"this is test!"]                                              ;    //把this的字体颜色变为红色    [attriString addAttribute:(NSString *)kCTForegroundColorAttributeName                        value:(id)[UIColor redColor].CGColor                        range:NSMakeRange(0, 4)];    //把is变为绿色    [attriString addAttribute:(NSString *)kCTForegroundColorAttributeName                        value:(id)[UIColor greenColor].CGColor                        range:NSMakeRange(5, 2)];    //改变this的字体,value必须是一个CTFontRef    [attriString addAttribute:(NSString *)kCTUnderlineStyleAttributeName                        value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble]                        range:NSMakeRange(0, 4)];    //给this加上下划线,value可以在指定的枚举中选择    [attriString addAttribute:(NSString *)kCTUnderlineStyleAttributeName                        value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble]                        range:NSMakeRange(0, 4)];    // 绘制路径    CGMutablePathRef path = CGPathCreateMutable();    CGPathAddRect(path, NULL, self.bounds);    // 创建绘制的字符串和CTFrame    CTFramesetterRef framesetter =    CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attriString);    CTFrameRef frame =    CTFramesetterCreateFrame(framesetter,                             CFRangeMake(0, [attriString length]), path, NULL);        // 绘制    CTFrameDraw(frame, context);        // 释放内存    CFRelease(frame);    CFRelease(path);    CFRelease(framesetter);    }

效果如下

到这里简单的自定义绘制就完成了~

 

转载于:https://www.cnblogs.com/tmacforever/p/4692545.html

你可能感兴趣的文章
【HTTP】Fiddler(三)- Fiddler命令行和HTTP断点调试
查看>>
镜像源归类
查看>>
IE下的document.onclick问题
查看>>
[模板]后缀数组
查看>>
git添加本地文件到github仓库
查看>>
0502《构建之法》第六、七章读后感
查看>>
[福大软工] Z班——Beta现场答辩反馈
查看>>
利用Pycharm本地调试spark-streaming(包含kafka和zookeeper等操作)
查看>>
Web控件
查看>>
状压DP泛做
查看>>
The New Stack:KubeEdge将Kubernetes的能力延伸至边缘
查看>>
Datatable的Select()
查看>>
Django之中间件
查看>>
博客作业05--查找
查看>>
SQL面试题目汇总
查看>>
为何img、input等内联元素可以设置宽、高
查看>>
Java知识总结---整合SpringMVC+Mybatis+Spring(二)
查看>>
android android:duplicateParentState="true" "false"
查看>>
HDU 3507 Print Article (斜率优化)
查看>>
Web 设计师的 50 个超便利工具(下)
查看>>