UITableView+FDTemplateLayoutCell源码解析

向作者致敬先附上git地址:https://github.com/forkingdog/UITableView-FDTemplateLayoutCell

写这篇文章的时候最新版为1.6(pod 'UITableView+FDTemplateLayoutCell', '~> 1.6')。

项目总共4个类文件,如下:


一:主类为UITableview+FDTemplateLayoutCell。看一下此类h文件所定义的东西


可以看出它就是通过分类的形式向UITableView中总共添加了5个方法。向UITableviewCell中添加了两个属性。

第一个方法fd_templateCellForReuseIdentifier: 这个方法用来获取模板cell,此cell职责就是用来计算高度。其实你在外部并不会用到这个方法,不知道作者为什么把这个方法暴露在外部(如果哪位看官知道何种情况下我们在外部需要用到此方法还请留言指教)。

第2,3,4个方法及时获取cell高度的方法,区别是第2个方法不使用高度缓存,第3个方法根据IndexPath缓存高度,第4个方法根据Key缓存高度,这个key是啥呢,就是你从服务器获取的获取的model列表,这个model中的可以唯一标示这个model的key。

第5个方法时用来获取UITableView的footer和header的高度的。这个方法是没有缓存高度的。

再来看看给UITableviewCell添加的两个属性。

fd_isTemplateLayoutCell这个属性为YES表示此cell是模板cell,模板cell只是用来计算的,不需要为它做UI方面的配置。你用第一个方法得到的cell就是模板cell。

fd_enforceFrameLayout这个属性默认为NO,为YES的话就是告诉第2,3,4个方法获取高度的时候不要使用-systemLayoutSizeFittingSize:方法,直接使用-sizeThatFits:方法。如果为NO则获取高度首选-systemLayoutSizeFittingSize:方法,如果-systemLayoutSizeFittingSize:方法获取的高度为0再使用-sizeThatFits:方法获取。

二:UITableView+FDIndexPathHeightCache和UITableView+FDKeyedHeightCache。这个两个类是缓存类,一个根据IndexPath缓存,一个根据Key缓存。

看一下这两个类的h文件定义了哪些东西:


indexPaht缓存
key缓存

首先都有5个方法,这5个方法的功能是一样的。

-existsHeightAtIndexPath:和-existsHeightForKey:是判断缓存是否已经存在。-CacheHeight:byIndexPath:和-cacheHeight:byKey:是保存高度缓存。-heightForIndexPath:和-heightForKey:是取缓存高度,如果缓存高度不存在,返回@(-1)。-invalidateHeightAtIndexPath:和-invalidateHeightForKey:用于删除单个特定缓存。-invalidateAllHeightCache用于删除全部缓存。

FDIndexPathHeightCache比FDKeyHeightCacha多了一个属性automaticallyInvalidateEnabled。这个属性的作用就是当你的UITableView调用-reloadDdata,-DeleteSections:withRowAnimation:,-deleteRowsAtIndexPaths:withRowAnimation:之类的操作时,就会自动删除对应的IndexPaths的高度缓存。虽然知道了这个属性的作用,但是查看保存缓存的方法-cacheHeightAtIndexPath:源码却发现是这样写的

这个方法里却把automaticallyInvalidateEnabled设为YES。那我们在外面再怎么设为NO,也会又被设为YES啊!不知道作者咋想的。

然后就是两个缓存类都通过分类的方式给UITableView添加了一个自己类型的缓存属性:fd_indexPathHeightCache和fd_keyHeightCache。

三:最后一个类就是UITableView+FDTemplateLayoutCellDebug。这个类就是用于打印debug信息的。这里就不多叙述了。

说完各个类的声明,接下来就进m文件看看具体实现。

一:UITableView+FDTemplateLayoutCell.m

就从-fd_heightForCellWithIdentifier: cacheByIndexPath: configuration:这个方法入手去看实现代码。如下:

我们忽略fd_debugLog方法不看。首先判断了一下UITableView持有的缓存类中(这个缓存类是懒加载的,首次调用创建)是否已经存在了对应IndexPath的高度缓存,如果以存在直接返回缓存中的高度。如果缓存中没有找到,那么就调用-fd_heightForCellWithIdentifier: configuration:去计算。然后将计算结果保存到缓存中,最后返回高度。我们先不管缓存类是怎么查找缓存和保存缓存的,之后我们会到缓存类中去研究。此处我们先去看看缓存中没有对应缓存的情况下,是怎么去计算高度的。进入方法-fd_heightForCellWithIdentifier: configuration:中:

首先根据identifier得到对应的模板cell:templateLayoutCell(有关模板cell的保存和创建很简单就不说了,大家自己一看代码便知)。得到templateCell之后先给用户一个机会去配置templateCell通过configuration(templateLayoutCell),配置什么呢,主要是给UILabel的text赋值啊之类的。好让接下来去计算具体高度。赋值好之后重点来啦,那就是[self fd_systemFittingHeightForConfigurateCell:templateLayoutCell]。这个就是具体怎么计算高度的方法了。进入这个方法(方法太长,三部分才能完整显示):


第一步,先把模板cell的宽度设为UITableView的宽度。

第二步,在使用-systemLayoutSizeFittingSize:方法前给cell.contentView加上一个宽度约束。如果是ios10.3以后的系统,还要给cell.contentView的上下左右到cell的边距设为0。最后调用-systemLayoutSizeFittingSize:方法获取高度,获取高度之后把之前加的约束全部删除。

第三步,如果第二步获取的高度为0的话,那么就执行-sizeThatFits:方法去获取高度,如果你想使用此方法获取正确高度,那你就需要在自定义cell中重写-sizeThatFits:方法了,具体怎么重写,你可以看demo。如果通过-sizeThatFits:获取的高度还是0呢!那么就返回系统默认的高度了,也就是44。至此,高度计算完成,返回高度。

二:UITableView+FDIndexPathHeightCache.m

以IndexPath缓存类为例来说,无非就是持有一个NSMutableArray<NSMutableArray<NSNumber *> *>类型的二维数组,然后将高度以NSNumber形式保存进数组。然后就是通过method_exchangeImplementations()截获UITableView的reloadData,DeleteSections:withRowAnimation:等方法,好在用户执行这些方法的时候判断是否删除对用IndexPath的高度缓存。如下图:

三:UITableView+FDKeyedHeightCache.m

key缓存就更简单了,使用NSMutableDictionary<id<NSCopying>, NSNumber *>类型的可变字典保存高度。

好了,关于UITableView+FDTemplateLayoutCell的源码解析就到这里,其实很简单。借此机会锻炼一下自己写此类文章。使用这个库最重要的部分还是在于自定义cell的时候,的布局和约束的添加,关于这部分大家可以到网上了解一下self-sizing cell这个概念。

最后欢迎大家阅后批评指导!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容