I have a UITableView with custom UITableViewCells. Each cell has a bunch of UIView, UIStackView, and UILabel subviews to build out the design I want.
Everything within the UITableViewCell is positioned using AutoLayout, and I allow the UITableView to automatically give height to the cells by doing:
tableView.estimatedRowHeight = 85
tableView.rowHeight = UITableViewAutomaticDimension
However, because of the complexity of the cell's subview layout, scrolling down the tableView is very laggy/choppy as each cell tries to estimate and build out it's correct height.
I read up on some articles that discuss these issues like:
https://medium.com/ios-os-x-development/perfect-smooth-scrolling-in-uitableviews-fd609d5275a5
This inspired me to try a different approach where I would calculate the height of each cell by adding up all the vertical space, and calculating dynamic string height by utilizing functions like the following, and then caching these heights in a dictionary of [IndexPath.row (Int), Row Height (CGFloat)].
extension String {
func heightWithConstrainedWidth(width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: CGFloat.max)
let boundingBox = self.boundingRectWithSize(constraintRect, options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: [NSFontAttributeName: font], context: nil)
return boundingBox.height
}
}
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
if let height = cellHeightCache[indexPath.row] {
return height
} else {
let data = dataItems[indexPath.row]
var height: CGFloat = 0
height += 20 // top padding above text
height += data.title.heightWithConstrainedWidth(tableView.frame.width - 72 * 2, font: UIFont.boldSystemFontOfSize(18)) // height of title
height += 20 // bottom padding below text
... // this goes on and on with if statements depending on if the data has a subtitle, image, other properties, etc to get the correct height for *that* cell
cellHeightCache[indexPath.row] = ceil(height)
return height
}
}
While this does work, now I am mixing frame calculations, tableView.frame.width - 72 * 2 with the AutoLayout of the cell's subviews to get the height. And because these are frame calculations, if the user rotates the device or on an iPad brings over the right split screen view, this clearly breaks. I could try and catch all these edge cases and recalculate when the user rotates/changes the size of the screen, but am I missing a way to calculate the height of these cells without using frames?
Is there anyway just using AutoLayout positioning I can calculate the height of the cells in the heightForRowAtIndexPath function?
Thanks