原文出自:标哥的技术博客
前言
最近还是有不少朋友老问Swift版的自动计算行高怎么做,大家使用SnapKit来自动布局时,都希望能够自动地计算出行高,不用每次都自己去算一篇。
本篇介绍笔者所开源的基于SnapKit这套自动布局库而写的一个扩展,用于自动计算行高。最重要的是,只要约束正确,就可以实现自动计算行高,而且当我们需要动态修改约束时,只要统一放在配置数据的API那里修改约束一样可以计算出正确的高度。
demo效果
千言万语,不如一个demo效果图,看完效果图再继续往下看:
库名HYBSnapkitAutoCellHeight
名称命名为HYBSnapkitAutoCellHeight,主要是区别于Masonry版本。关于Masonry自动计算行高的版本,大家可以阅读:HYBMasonryAutoCellHeight,它是Objective-C写的。
设计思路
既然我们使用的是自动布局,那么就可以利用自动布局来准确地计算出位置。要想通过自动布局立即得到位置和大小,那么就需要调用layoutIfNeeded
方法,这样就可以获取所有控件的frame
了。
既然可以通过此方法获取到所有控件的frame
了,那么我们若指定某一个视图为最后一个视图,作为参考,那么就可以直接通过获取该视图的frame来计算高度了。但是,如果我们并不是与指定的视图的位置平齐怎么办?没有关系,我们提供了另外一个属性用于设置最后一个参考视图与cell的最底部的间隔是多少。
我们指定如下两个属性:
public var hyb_lastViewInCell: UIView? {
get {
let lastView = objc_getAssociatedObject(self, &__hyb_lastViewInCellKey);
return lastView as? UIView
}
set {
objc_setAssociatedObject(self,
&__hyb_lastViewInCellKey,
newValue,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
}
public var hyb_bottomOffsetToCell: CGFloat? {
get {
let offset = objc_getAssociatedObject(self, &__hyb_bottomOffsetToCell);
return offset as? CGFloat
}
set {
objc_setAssociatedObject(self,
&__hyb_bottomOffsetToCell,
newValue,
.OBJC_ASSOCIATION_ASSIGN);
}
}
这两个是通过runtime添加的属性,因为扩展并不能添加属性。由于swift中关联值所使用的key是个指针,因为我们的参数应该是传一个地址,比如我们定义的key是__hyb_lastViewInCellKey
,它是String类型的,而String类型是结构体类型,但是实际应该是要传一个指针,因此需要传这个字符串的地址过去。
单API
对外只提供了一个API,而且还是类方法:
/**
唯一的类方法,用于计算行高
- parameter indexPath: index path
- parameter config: 在config中调用配置数据方法等
- returns: 所计算得到的行高
*/
public class func hyb_cellHeight(forIndexPath indexPath: NSIndexPath, config: ((cell: UITableViewCell) -> Void)?) -> CGFloat {
let cell = self.init(style: .Default, reuseIdentifier: nil)
if let block = config {
block(cell: cell);
}
return