我的学习笔记的参考来源来自唐巧的博客,今天早上开始学习他在基础篇所讲的排版引擎框架,首先我看到了这个"单一功能原则",在维基中的解释是规定每一个类有一个单一的功能,并且这个功能应该有这个类完全分装起来.所有它的服务都应该严密的和该功能平行(功能平行,表示没有依赖).简单的理解就是,一个类支付则一个功能的管理,外界其他因素的变化不会导致它的改变.只有一个原因能够改变的类就符合这个"单一功能原则".降低类与类之间的耦合度.虽然我们都知道这个原则,但在实际开发中将其贯彻执行下去的却很少做到.所以我们要进行多练习利用这个原则进行类的封装.好了蛋扯了这么多,还没有到我们的正题上.
回到正题:唐巧在这个demo中将上一节笔记中的demo进行了拆分,按照单一原则进行了封装.
他讲上述功能分为四个类来完成.
1.一个是用于显示的类,他只负责显示内容,并不负责排版和数据
2.一个模型类,用于承载显示所需要的所有数据
3.一个排版类,用于实现文字内容的排版.
4.一个配置类,用于实现排版时的可配置项.
它们所对应的文件都是1.CTFrameParserConfig类,用于配置绘制的参数,例如文字的颜色,大小,行间距等.2.CTFrameParser类,用于生成最后会知道界面上所需的CTFrameRef实例.3CoreTextData类,用于保存有CTFrame类生成的CTFrameRef实例以及CTFrame是机会只需要的高度.4.CTDisplayView类,持有CoreTextData类的实例,负责将CTFrameRef绘制到界面上.
好了,代码我已经都写好了,现在我们就进行代码分析,从每一行代码出发来学习唐巧的这一篇博客.我会对每一个方法作出明确的解释.希望能帮助大家在以后的使用工程中,方便理解.
从配置参数的类看起,他定义了四个属性宽度,字体大小,行间距字体颜色.
并重写了NSObject的init方法,在init方法中初始化了这些配置属性.
这段代码比较简单就不多解释了,就是给属性服了初始值.
现在要分析的这个类,是这个demo的关键,他负责的任务是生成CTFrameRef实例.
在这个类的内部会用到很多CoreText的方法,现在我们就开始学习第一个方法吧.
先看头文件.
我们看到这个类使用@class告诉这个文件这两个类存在,并没有直接使用#import,在这里就简单说一下两者区别,#import在引入头文件时,会将文件整个copy到现在的文件当中,会有效率问题,但是他避免了递归引入的问题.@class只是告诉该文件,我这个文件已经存在了,在写代码时只要不调用到引入的文件的方法,就不会出现错误.这样可以减少编译效率,只有在真正需要使用的时候才使用#import来引入头文件.好了想去了解(http://www.saitjr.com/ios/oc-include-import-class-difference.html)自己查看吧.
我们先看第一个方法,它的返回值是一个CoreTextData类型,也就是我们的用来保存CTFrameRef和绘制高度的类.第一个参数是字符串,第二个参数是我们刚才说的配置类,好了先不看实现文件我们大概猜一下这个方法到底是干什么的.我们一看返回值和参数就有了大概的苗头,明显是这个方法是将我们传入的NSString对象经过config参数配置后经过一系列操作最终生成CTFrameRef对象和需要的高度,保存到返回值的实例当中.而这些一系列操作就是我们上一篇讲的那些,1.生成绘制文本,填充区域3.然后计算需要的文本高度.4,生成文本框架.无非就这些操作.有了这些思路.现在请先记住这些思路,然后我们看其他的方法.
先看第三个方法,和第一个方法基本类似,并没有多大的区别.只是第一个传入的参数变成了属性字符串.和刚才对比我们发现,可能这个方法和上一个方法的内部实现差不了多少,我们前面介绍过CoreText支持属性字符串,并不支持字符串,所以第一个方法的实现就是讲字符串经过转换生成属性字符串,然后后面的操作都是一样的了.
在看第二个方法,返回值是一个字典,我们先想一下,这里需要字典来干什么,并不需要他来做什么,但是在前两个方法再转换成属性字符串的时候需要一个attributeds的参数刚好是有字典构成的.一拍即合我们就姑且认为这个就是返回创建属性字符时所需的那个参数字典的.
好了我们进入.m文件去看一下实现吧
首先看一下第一个方法:
首先我们看到它先调用了第三个方法,然后在创建一个属性字符串.刚好第二个参数就是调用第三个方法返回的,证明我们刚才猜对了,好了,再看返回的时候他调用了一个方法,这个方法刚好是第三个方法:我们来研究一下第三个方法到底干了什么.第二个方法一会再给大家解释,先解释第三个方法.
1.先看第一步创建这个东西我们在上一次的学习笔记中已经说过了是一个排版器.他的创建依赖刚才的属性字符串.
2.获取绘制时所需要的高度,我们知道NSString和属性字符串都有计算高度的方法,但是这个我们还没有接触过到底怎么计算啦,好我们一步步解释这些方法.创建一个CGSize对象,一个是配置的宽度和最大的高度.
3.CTFramesetterSuggestFrameSizeWithConstraints在文档中的解释的含义是:需要用多少空间来显示这个字符串.可以约束空间维度.
第一个参数是:排版器,第二个参数是:字符串的适用范围,在创建框架时使用,如果长度范围设置为0,就会继续添加行,知道空间和范围被使用完.第三个参数是:额外的控制框架创建的属性.如果为nil表示没有这样的额属性.第四个是看度和高度的限制如果使用则表示没约束.这里我们对高度是没有约束的.第五个参数是包含字符串的范围,这里一般设置为nil.
获取到所需要的空间后,我们获取所需绘制区域的高度.
接下来就是创建左后需要保存到返回值CoreTextData中的CTFrameRef.这里调用了一个私有方法用来创建框架.
第一句是新建一个可变的路径,然后通过CGPathAddRect来添加一个矩形的绘图区域.参数是可变路径,第二个参数是形变量,这里设置为NULL,第三个参数是矩形区域.
接下来就是创建CTFrameRef框架,参数分别是排版器,字符串的适用范围,如果为0就会自动添加行,直到空间范围用完.第三个参数是矩形区域,第四个参数是额外的属性,用来限制框架的.
然后释放path,返回CTFrameRef实例.
返回后保存到CoreTextData的实例中并且将区域高度保存到实例中,释放排版器和框架,并且返回CoreTextData实例.
好了我们再来看第二个函数到底做了什么.
首先第一部分是设置绘制文本时的字体大小和字体.
第二部分是设置行间距CTParagraphStyleSetting这个是一个结构体,我们看到的spec指的是说明符,有很多种就不一一解释了自己去看吧
valueSize:值字段的大小,这个值必须匹配值的大小CTParagraphStyleSpecifier在规范中设置所需的字段。
value:引用规范所指定的设置字段的值。的值必须在适当的范围内规范价值,至少在valueSize指定的大小一样大。
CTParagraphStyleCreate创建段落样式第一个参数是段落设置,第二个是设置的个数
第三部分是将设置的字体颜色,字体和段落样式等保存到字典中
最后释放段落样式和字体样式返回设置属性字典.
好了到这里基本上第二个用于排版的类就说完了.
第三个类就是数据类:
头文件中包含一个CTFrameRef属性,一个height和一个属性字符串,在第二个类中我们已经给这三个属性分别赋过值了,如果忘记了,请返回上面再看一次.
好了再看.m文件
看到了一个setter方法和dealloc方法.
看到这个setter方法,犹如回到了mrc的时代,先判断两个是否相等,在判断是否为nil如果不为nil就释放,然后在retain新值,在赋值.
在dealloc中也是判断如果不为nil就释放.
好了第三个类就是这么简单,
再看第四个
CTDisplayView类,就是专门管理绘制的类
它的头文件很简单就有一个CoreTextData属性.
在实现文件重写drawRect方法
CGContextRefref =UIGraphicsGetCurrentContext();
//反转坐标系
CGContextSetTextMatrix(ref,CGAffineTransformIdentity);
CGContextTranslateCTM(ref,0,self.bounds.size.height);
CGContextScaleCTM(ref,1.0, -1.0);
if(self.data) {
CTFrameDraw(self.data.ctFrame, ref);
}
获取上下文反转坐标系,判断需要绘制的数据是否存在,如果存在就绘制到界面上.
在看一下Controller需要做哪些工作
引入#import"CTFrameParserConfig.h"
#import"CTDisplayView.h"
#import"CTFrameParser.h"头文件,在storyBoard中拖一个视图,然后关联,视图的类型对应CTDisplayView
然后再viewDidLoad中配置数据
切记在sb中将userAutoLayout关掉,要不然会出现问题,因为自动约束会将布局的书记拖后,所以在viewDidLoad中的设置高度就白费了.
完成狗的效果就是这样的.
这个东西比较难,而且博客也很少,我准备花一段时间学习,先从学习别人的博客开始.最后希望能够自己写一个关于阅读器的demo.
如果还有什么没有理解或者是有什么更好的想法的可以评论或与我联系.如果喜欢文章或者想了解更多的关于CoreText的内容就请动动小手,点下关注,不会怀孕的,不要怕!带走想要的知识,留下你们的❤️.
谢谢
本人联系方式:qq:513961360
email:513961360@qq.com
也可以加我们的qq群希望能与朋友们一起聊天和学习.群里还有很多iOS开发者,帮助我们解决问题,并且同时学习.
qq群号:580284575