初识CoreText
一、基本知识介绍
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的文档 Glyph metrics,其实iOS就是使用Free Type库来进行字体渲染的。
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, , 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, , 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(, [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,2
const CFStringRef kCTForegroundColorAttributeName;
//字体颜色属性 必须是CGColor对象,默认为black
const CFStringRef kCTForegroundColorFromContextAttributeName;
//上下文的字体颜色属性 必须为CFBooleanRef 默认为False,
const CFStringRef kCTParagraphStyleAttributeName;
//段落样式属性 必须是CTParagraphStyle对象 默认为NIL
const CFStringRef kCTStrokeWidthAttributeName;
//笔画线条宽度 必须是CFNumberRef对象,默为0.0f,标准为3.0f
const CFStringRef kCTStrokeColorAttributeName;
//笔画的颜色属性 必须是CGColorRef 对象,默认为前景色
const CFStringRef kCTSuperscriptAttributeName;
//设置字体的上下标属性 必须是CFNumberRef对象 默认为0,可为-1为下标,1为上标,需要字体支持才行。如排列组合的样式Cn1
const 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, , 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(, )];
//把is变为绿色
[attriString addAttribute:(NSString *)kCTForegroundColorAttributeName
value:(id)[UIColor greenColor].CGColor
range:NSMakeRange(, )];
//改变this的字体,value必须是一个CTFontRef
[attriString addAttribute:(NSString *)kCTUnderlineStyleAttributeName
value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble]
range:NSMakeRange(, )];
//给this加上下划线,value可以在指定的枚举中选择
[attriString addAttribute:(NSString *)kCTUnderlineStyleAttributeName
value:(id)[NSNumber numberWithInt:kCTUnderlineStyleDouble]
range:NSMakeRange(, )];
// 绘制路径
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, self.bounds);
// 创建绘制的字符串和CTFrame
CTFramesetterRef framesetter =
CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attriString);
CTFrameRef frame =
CTFramesetterCreateFrame(framesetter,
CFRangeMake(, [attriString length]), path, NULL);
// 绘制
CTFrameDraw(frame, context);
// 释放内存
CFRelease(frame);
CFRelease(path);
CFRelease(framesetter);
}
效果如下

到这里简单的自定义绘制就完成了~
初识CoreText的更多相关文章
- Android动画效果之初识Property Animation(属性动画)
前言: 前面两篇介绍了Android的Tween Animation(补间动画) Android动画效果之Tween Animation(补间动画).Frame Animation(逐帧动画)Andr ...
- 初识Hadoop
第一部分: 初识Hadoop 一. 谁说大象不能跳舞 业务数据越来越多,用关系型数据库来存储和处理数据越来越感觉吃力,一个查询或者一个导出,要执行很长 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- 初识IOS,Label控件的应用。
初识IOS,Label控件的应用. // // ViewController.m // Gua.test // // Created by 郭美男 on 16/5/31. // Copyright © ...
- UI篇(初识君面)
我们的APP要想吸引用户,就要把UI(脸蛋)搞漂亮一点.毕竟好的外貌是增进人际关系的第一步,我们程序员看到一个APP时,第一眼就是看这个软件的功能,不去关心界面是否漂亮,看到好的程序会说"我 ...
- Python导出Excel为Lua/Json/Xml实例教程(一):初识Python
Python导出Excel为Lua/Json/Xml实例教程(一):初识Python 相关链接: Python导出Excel为Lua/Json/Xml实例教程(一):初识Python Python导出 ...
- 初识SpringMvc
初识SpringMvc springMvc简介:SpringMVC也叫Spring Web mvc,属于表现层的框架.Spring MVC是Spring框架的一部分,是在Spring3.0后发布的 s ...
- 初识redis数据类型
初识redis数据类型 1.String(字符串) string是redis最基本的类型,一个key对应一个value. string类型是二进制安全的.意思是redis的string可以包含任何数据 ...
- Redis初识、设计思想与一些学习资源推荐
一.Redis简介 1.什么是Redis Redis 是一个开源的使用ANSI C 语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value 数据库,并提供多种语言的API.从2010 年 ...
随机推荐
- 关于 unity5.3.1 录制 animation 带有 rotation 信息打包 Android 会运动错乱的问题
Unity5.3.1 录制 animation 带有 rotation 信息打包 Android 会运动错乱的问题 ,临时解决方法是:在动画面板中点击 rotation 属性,右键选择菜单中 ...
- makefile 中 $@ $^ %< 使用
这篇文章介绍在LINUX下进行C语言编程所需要的基础知识.在这篇文章当中,我们将会学到以下内容: 源程序编译 Makefile的编写 程序库的链接 程序的调试 头文件和系统求助 1.源程序的编译 在L ...
- Java笔记(二十二)……Collection集合
概述 为什么会出现集合类 面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式 数组和集合类同是容器,有何不同 数组虽然也可以存储 ...
- iOS设备的硬件适配 (关于armv6, armv7, armv7s ) <转>
<转> http://blog.csdn.net/smking/article/details/8148702 1.OpenGL ES版本支持 iPhone:iPhone 3G以下(包 ...
- 从app里跳到appstore评论页面的实现
// 如果要实现在应用里面跳到appstore的对应评论页面里面的话,只要将下面地址中App_ID替换成自己的id就可以了,其他的地方都不用管. // 如果要用Safari浏览器做实验的话可以将地址中 ...
- 深入浅出Android动态载入jar包技术
在实际项目中.因为某些业务频繁变更而导致频繁升级client的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路.将核心的易于变更的业务封装在jar包里然后通过网络下载下来 ...
- HDU 4849-Wow! Such City!(最短路)
Wow! Such City! Time Limit: 15000/8000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Other ...
- linux编译安装LAMP
Linux安装Apache+MySQL+PHP 安装部分依赖 安装apr(可选) # tar -xf apr-1.5.0.tar.bz2 # cd apr-1.5.0 #./configure --p ...
- MySQL性能监控工具-MONyog
1.登录配置界面 2.show processlist 查看当前使用的进程 3.警告建议你应该优化哪些参数. 4.介绍一下慢查询的配置,其它的可以自己配置,都是简单的英文. 该工具,用着还不错.其 ...
- phpcms 源码分析四: 数据库类实现
这次是逆雪寒的数据库类分析: <?php /* 这个讲 phpcms 的数据库类 和 phpcms 的文本缓存的实现.看了看 都是很简单的东西.大家看着我注释慢慢看吧.慢慢理解,最好能装了PHP ...