Self Sizing Table View Cells — Programmatically
Updates: Updated article and project to Swift 3.0
There are many posts online on how to configure a dynamic tableview cell using interface builder; however, there are not nearly as many for programmatic ones. And since we have NSLayoutAnchor, things have never been easier! By the end, you will know how to create tableview cells of dynamic height based on label content using AutoLayout.
Starter Project
To kick things off, let’s begin with the following starter project. The application has removed Storyboard and pushes the View Controller onto the navigation controller within the app delegate. The main files we will be interacting are as follows
- Book.swift — model class containing a book’s name and details
- BookTableViewCell.swift — Empty UITableViewCell subclass conforming to UITableViewDataSource Protocol
- BookDataSource.swift — Contains class method for generating a book list
- ViewController.swift — Empty ViewController subclass
Configure TableView
Within the function configureTableView(:), add the following code
tableview.estimatedRowHeight = 100tableview.rowHeight = UITableViewAutomaticDimensiontableview.registerClass(BookTableViewCell.self, forCellReuseIdentifier: bookCellReuseIdentifier)
By updating the estimatedRowHeight property, we have gained the following effect:
Note we have also set the tableview’s rowHeight property. By doing so, we have can expect the self-sizing behavior for a cell. Furthermore, I have noticed some developers override heightForRowAtIndexPath to achieve a similar effect. This should be avoided for the following reason.
The registerClass simply registers our BookTableViewCell with an identifier.
By using NSLayoutAnchor, we will pin the tableview’s anchors to its superview. Add the following code within configureTableView(:)
view.addSubview(tableview) tableview.translatesAutoresizingMaskIntoConstraints = falsetableview.topAnchor.constraint(equalTo: view.topAnchor).isActive = truetableview.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = truetableview.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = truetableview.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
Now that the tableview is correctly positioned, we can focus on the cell.
Configure TableViewCell
The key is to use the correct constraints to create the dynamically sized cells. We will first configure the titleLabel by adding the following code within the provided init
let marginGuide = contentView.layoutMarginsGuide// configure titleLabelcontentView.addSubview(nameLabel)nameLabel.translatesAutoresizingMaskIntoConstraints = falsenameLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = truenameLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = truenameLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = truenameLabel.numberOfLines = 0
There are some key points to note here.
- I am adding the views to the contentView, not the view itself
- I am setting the numberOfLines to inform iOS it can be of multiple lines
- I am using the marginGuide’s anchor instead of the view’s anchors so the recommended padding is utilized
- The bottomAnchor has not been set because it will relate to the detailLabel and not the marginGuide
Now we will configure the remaining label with the appropriate constraints
contentView.addSubview(detailLabel)detailLabel.translatesAutoresizingMaskIntoConstraints = falsedetailLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = truedetailLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = truedetailLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = truedetailLabel.topAnchor.constraint(equalTo: nameLabel.bottomAnchor).isActive = truedetailLabel.numberOfLines = 0detailLabel.font = UIFont(name: "Avenir-Book", size: 12)detailLabel.textColor = UIColor.lightGrayColor
As noted above, the nameLabel’s bottomAnchor is constrained to the detailLabel’s topAnchor. That is all it really takes to create dynamically self sizing cells with AutoLayout.
Test
Now you may run the application and see the following dynamic cells in action. The complete GitHub project is available here.