Home

UITableViewCell Automatic Height

 
Posted on April 18 2015

One of the memories of WWDC last year for myself was sitting in the auditorium and listening about allowing iOS to calculate the height for each of the UITableViewCell's inside a UITableView and thus allow for the developer to no longer implement the delegate to calculate the height for the row at each indexPath. This functionality is definitely useful if apple implemented it correctly and there were no underlying bugs in it. With iOS8.3 the solution finally seems to be stable and not have any issues with the UIScrollView content offsets when coming back to the UIViewController holding the UITableView from another UIViewController.

How It Works

Under the hood, Apple have utilized AutoLayout to calculate the automatic height of the row during the creation of each UITableViewCell. In order for Automatic Cell Height to work you need to configure the following in an application.

Implementation

In order for the UITableView to calculate the size automatically you need to set up the estimated height per row and the row height to the special apple constant UITableViewAutomaticDimension as shown in the code snipet below.

tableView.estimatedRowHeight = 166.0 // 1.
tableView.rowHeight = UITableViewAutomaticDimension // 2.
Here is what is occurring in the code above:
  1. Provides as accurate as possible the estimated height of each row
  2. Allows the UITableView to return the rowHeight based off information from the UITableViewCell
The above code is all the configuration that you need to do in order for the UITableView to use automatic calculations for the rowHeight per row.

UITableViewCell Setup

The UITableViewCell must provide enough information through its AutoLayout constraints so the UITableView can calculate the height of the cell when it has been configured with all of its data. You can do this either through a Storyboard or alternatively through the code. For this blog we will show how to do it through the code but the same principals apply to the Storyboard. Go to File -> New -> File and you will see the screen below:


Choose the iOS -> Source -> Cocoa Touch Class and hit the "Next" button.

Name the file approriately for the case of this demo it has been named "DTFAutomaticTableViewCell" and click the "Next" button

For demonstration purposes we will put two UILabel objects into the UITableViewCell's contentView and setup their constraints.

    // 1.
    private lazy var titleLabel: UILabel = {
        let label = UILabel()
        label.setTranslatesAutoresizingMaskIntoConstraints(false)
        label.textAlignment = .Left
        label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline)
        return label
    }()
    // 2.
    private lazy var descriptionLabel: UILabel = {
        let label = UILabel()
        label.setTranslatesAutoresizingMaskIntoConstraints(false)
        label.textAlignment = .Left
        label.numberOfLines = 0
        label.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
        return label
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        // 3.
        contentView.addSubview(titleLabel)
        contentView.addSubview(descriptionLabel)
        setupConstraints()
    }

    private func setupConstraints() {
        // 4.
        let viewsDictionary = ["title":titleLabel, "description":descriptionLabel]
        // 5.
        let metrics = ["titleHeight":17.0,
            "leadingMargin" : 15.0,
            "trailingMargin" : 5.0,
            "verticalSpacing" : 8.0]

        // Setup the title label horizontal constraints
        NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
            "|-(leadingMargin)-[title]-(trailingMargin)-|",
            options: NSLayoutFormatOptions(0),
            metrics: metrics,
            views: viewsDictionary))

        // Setup the description label horizontal constraints
        NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
            "|-(leadingMargin)-[description]-(trailingMargin)-|",
            options: NSLayoutFormatOptions(0),
            metrics: metrics,
            views: viewsDictionary))

        // Setup the title and description label vertical constraints
        NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
            "V:|-(verticalSpacing)-[title(titleHeight)]-(verticalSpacing)-[description]-(verticalSpacing)-|",
            options: NSLayoutFormatOptions(0),
            metrics: metrics,
            views: viewsDictionary))
    }
Here is what is occurring in the code above
  1. Setting up a UILabel that will hold title information. This is setup lazily so most of the configuration is in one place and not spread through your class.
  2. Setting up a UILabel that will hold the description information the one difference with this one is the numberOfLines is set to 0. This will allow the UILabel to grow vertically with the contents it has inside of it. This is setup lazily so most of the configuration is in one place and not spread through your class.
  3. Adding both the title and description UILabel's to the UITableViewCell's contentView.
  4. Setting up the views dictionary so the views can be referenced when using AutoLayout visual format which is similar to ASCII art.
  5. Setting up the metrics which are constants to be accessed while writing the AutoLayout visual format. This keeps everything neat and allows you to use constants so you change the code in one place vs multiple places.
The code at the bottom of the "setupConstraints" function sets the AutoLayout constraints on each of the views. Lets take a look at that in more depth.
    // Setup the title label horizontal constraints
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "|-(leadingMargin)-[title]-(trailingMargin)-|",
        options: NSLayoutFormatOptions(0),
        metrics: metrics,
        views: viewsDictionary))
The above code is dealing with the "titleLabel" UILabel specifically its horizontal constraints:
    // Setup the description label horizontal constraints
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "|-(leadingMargin)-[description]-(trailingMargin)-|",
        options: NSLayoutFormatOptions(0),
        metrics: metrics,
        views: viewsDictionary))
The above code is dealing with the "descriptionLabel" UILabel specifically its horizontal constraints: Based off the above AutoLayout constraints the "titleLabel" and the "descriptionLabel" will both be 15 pixels from the contentView's left side and 5 pixels from the contentView's right side. They are both free by the AutoLayout constraints to make sure their width is always the width of the contentView - 20 pixels to account for the 15 left and 5 right pixel spacings.

Now that the horizontal constraints are setup the remaining piece is to setup the vertical constraints in order for iOS to be able to automatically calculate the height for the UITableViewCell.

    // Setup the title and description label vertical constraints
    NSLayoutConstraint.activateConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|-(verticalSpacing)-[title(titleHeight)]-(verticalSpacing)-[description]-(verticalSpacing)-|",
        options: NSLayoutFormatOptions(0),
        metrics: metrics,
        views: viewsDictionary))
Now based off all of the constraints set iOS now has the ability to determine the height for the UITableViewCell and hence this can be used in the UITableView without having to implement the delegates as was the previous implementation.

Conclusion

Apple definitely made a big leap in maintainability for developers with this functionality since now we no longer have to perform the calculations ourselves but instead provided we setup the constraints correctly on our UITableViewCell's we will get this functionality for free. A link to a demonstration project is provided here. This demo project provides a list of countries in the world with descriptions of different sizes for each country and thus the UITableView is calculating the heights for the UITableViewCell's automatically.



Main Page