Avoiding layout errors with UITableViewCell / AutomaticDimension
Luke, 9 Dec 2019
My preferred method for UITableViewCells is to give them their own xib file. Firstly its just good practise when working in a team of iOS devs, to use separate xib’s where possible, because it means no merge errors for the storyboard when your branch is merged back to develop. But for a UITableView anyway, if you have several cells to set out, its easier to do it in an xib than in a storyboard, due to space constraints. Theres only one additional step when using an xib over a storyboard – registering the nib, one line of code.
But Ive also found I can get Autolayout errors, when setting up the constraints, and Im not sure whether this is confined just to xib’s – so heres a quick overview of Autolayout for UITableViewCells, so they resize correctly and without the dreaded ‘some of these constraints may clash..’ type errors.
First, create .xib file, and accompanying Swift file for your UITableViewCell subclass.
class GSTextViewCell: UITableViewCell {
override func prepareForReuse() {
}
}
Then in your xib, drag in a UITableViewCell object, and change its class to the one you just created in the Swift file.
You also need to set up the identifier used to create the cell, in the tab next to that one. For simplicity, I tend to use the same Identifier as the class name :
Then setup up the constraints within the cell – and heres the important part, which I dont see mentioned anywhere, but which is the only way to ensure that you dont get layout errors in the console when displaying these cells.
Set the priorities for at least one of the height constraints, so that the priority is below 1000. Weird you might think. But theres a clash between the constraints you set here, and an intrinsic constraint that UITableView uses when displaying the cell, which is called ‘UIView-Encapsulated-Layout-Height’. By lowering one of your height constraint priorities like this, it allows this clash to be resolved.
Your cell height is still created automatically though, as long as you also do the following :
func setupTableView() {
self.tableView.rowHeight = UITableView.automaticDimension
self.tableView.estimatedRowHeight = 60.0
self.tableView.register(UINib.init(nibName: "GSTextViewCell", bundle: nil), forCellReuseIdentifier: "GSTextViewCell")
}
So in that code, the tableview displaying your cell is setup to use automatic dimension calculation for the height – i.e. it uses the Autolayout setup in the cell, including the cells’ height. EstimatedRowHeight is used for another purpose : when the UITableView is setting up to display, it has to decide how many cells to go and create based on the size of itself. It uses this value to do that calculation – so if the tableview is 300px high, and you have 60px as the estimated row height, the UITableView will go and load at least 5 UITableViewCells before it needs to display them, to ensure they are ready. Finally the xib file we have created is registered, along with the reuse identifier we set earlier.
Thats all there is to it- you can set your UITableViewCell subclass to any size in the xib, and as long as you allow for a slightly lower priority height constraint, you wont get any errors either.