目录
手写代码和IB处理tableView动态行高
手写代码情况下,需要考虑的方面:
一、label单行与多行的区别
二、手写label背景填充跟着字来是否麻烦?
三、单行情况下,文字带中文,设置行间距,计算出的高度不准确。
备注
tableView是我们常用的控件之一,我们来谈一谈对于其行高的动态设置。
手写代码:
[string boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:nil].size
IB:
设定位置,不设定固定高,editor中设置sizeToFit,在heightForRow方法中给cell赋值后调用layoutIfNeeded方法。
(若想背景填充跟着字来,设置label的width的less than最大宽度,字数不足一行的,约束也会自动缩到与label长度匹配)
由于heightForRow会调用多次,在heightForRow中给cell赋值和调用layoutIfNeeded,性能会比较差。
解决方案:
1、根据id缓存每行的高度
2、设置预估行高
方案1、减少了调用cell赋值和layoutIfNeeded,性能相对提升。但是在获取行高的方法里进行了cell的赋值,结构上不合理。
方案2、在固定行高的情况下合适,动态行高的情况由于预估行高和实际行高的不同会出现列表跳动。这样说来,在固定行高的情况下设置预估行高能减少heightForRow的调用,提升性能。
手写和IB的区别:
手写:仅仅是计算;
IB:程序一启动就会全部加载进内存由系统托管,先强制布局然后看占了多大的尺寸。
使用手写代码的时候,有些东西需要考虑一下:
一、label单行与多行的区别
使用NSStringDrawingUsesLineFragmentOrigin
官方文档的描述:
To correctly draw and size multi-line text, pass NSStringDrawingUsesLineFragmentOrigin in the options parameter.
多行文本draw或者获取高度,需要有NSStringDrawingUsesLineFragmentOrigin在options参数中
我看到有不少人使用了NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading
不明白为什么要这样使用?先看看官方文档对两个选项的描述:
NSStringDrawingUsesLineFragmentOrigin
The specified origin is the line fragment origin, not the base line origin
指定的原点是行片段的原点, 而不是基线原点。
NSStringDrawingUsesFontLeading
Uses the font leading for calculating line heights
使用字体行距计算行高。
我看到文章有提出
1、NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading这种能解决有时高度不准的问题
2、在textView中,显示行数是10行,使用NSStringDrawingUsesLineFragmentOrigin时只计算出了5行的高度,而使用NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading计算出了10行的高度
针对这两个情况:
1、目前我使用中文、英文和中英文混合,使用NSStringDrawingUsesLineFragmentOrigin和使用NSStringDrawingUsesLineFragmentOrigin|NSStringDrawingUsesFontLeading的效果一样。
2、我通过UIFont获取字高度,textView显示了多少行,算出这几行的高度,然后这些文字通过boundingRectWithSize:options: attributes: context:方法计算一下高度,发现使用NSStringDrawingUsesLineFragmentOrigin没问题。
UIFont中找到了两个属性:ascender、capHeight。第一个可以得到中文字体的实际显示大小,第二个可以得到英文字母和数字的实际显示大小
这样看来使用要不要NSStringDrawingUsesFontLeading都一样,如果有不同的意见,请在下方评论。
二、刚刚看IB背景填充跟着字数来好像很简单,那么手写label背景填充跟着字来是否麻烦?
使用attributedText即可,好像也不麻烦。
三、单行情况下,文字带中文,设置行间距,计算出的高度不准确。
那么看看我们需要先确定的判断条件:
1、是否设置行间距;
2、是否是单行;
3、是否带中文;
那么如果满足这三种情况的话,我将size高度中的lineSpacing减掉不就可以了,那么看代码
这个时候运行后会发现还是有问题,size对了,但是label设置attributedText时带了lineSpacing,字的显示不对,那么我需要将attributedText中的lineSpacing也去掉。
这个时候没问题了。以上方法都放在NSString+Private文件中。
备注:
官方文档:
This method returns fractional sizes (in the size component of the returned CGRect); to use a returned size to size views, you must raise its value to the nearest higher integer using the ceil function.
获取的CGRect的值用一下ceil方法