本篇文章为CoreText系列的第三篇,讨论下纯文本排版的一些细节,会有中文,英文,数字以及emoji表情。主要涉及到使用CTLineDraw来一行一行的绘制,而非之前CTFrameDraw一气呵成,因为CTFrameDraw会因为行高不一致导致排版不美观,CTLineDraw尽管依然存在行高不一致的问题,但却可指定每行的行高保持一致以使得排版相对美观,毕竟,英文和中文字符的ascent,descent本来就不一样。
使用CTLineDraw来一行一行的绘制时,最重要的就是在绘制前设置CoreText的坐标的Y值,这也是本文的重点所在。
本文的代码放在了github的仓库。
贴一下字形图:
在设置坐标时,需要注意的是,CoreText的origin是在图中的baseLine处的。
分行绘制的原理主要就是从CTFrame中获得每一个CTLine对象,并针对每一个CTLine设置好该行的坐标,然后利用CTLineDraw函数进行绘制。
主要使用到的函数为:
CTFrameGetLines,传入CTFrame,返回一个装有多个CTLine对象的数组。
CTFrameGetLineOrigins,传入CTFrame,CFRange,和一个CGPoint的结构体数组指针,该函数会把每一个CTLine的origin坐标写到数组里。
CGContextSetTextPosition,设置CoreText绘制前的坐标。
CTLineDraw,绘制CTLine。
我这里分了两种实现方式
第一种只按照系统的方式来排版
自己设定一个行间距之后不去理会行高,每一个CTLine直接绘制.其实就相当于把CTFrameDraw要做的事情分步来实现而已。
其实现效果图为:
计算高度的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
|
绘制的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
|
另一种实现方式是指定每一行的高度为固定值
其效果图为:
计算高度代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
|
绘制的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
|
设置字符串全局样式的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
|
两个全局变量:
1 2 3 4 5 |
|
控制器里的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
内部封装的计算高度的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
要注意的是,以上不同绘制方式所需要的高度是不一样的,这点在demo中有做区别。我使用了type来区分不同的高度计算方式。同时,第一种方式,是有设置CTLine之间的行间距的,我这里设置的是5。而第二种方式是没有设置行间距的,只设置了每行的高度。
为了方便两种方式的区别,这里来一张整合图吧:
第一种方式为左图,第二种方式为右图。尽管第二种方式有额外的工作量,比如上面的1.4
这个全局变量,改变字体排版可能会变化等,但整体上还是觉得第二种排版方式美观一些。如果有同学知道其他方便的排版方式,也烦请告知下,thanks。
在学习分行绘制的过程中得到了泰尼叔和Naituw的帮助,这里一并表示感谢。
参考链接: