Animating UITableViewCell size and text change using Auto Layout and automatic dimension

Kamil Burczyk
Grand Parade
Published in
3 min readApr 8, 2017

In my recent iOS project I’ve had a view where content was presented as vertically scrollable cards and each of them could be expanded to show more details.

I’ve modelled entire solution as a UITableView where each cell contained vertically stacked subviews (I couldn’t use UIStackView due to iOS 8 support) and each subview was initialized with its own view model (but it’s just an implementation detail).

In the end view hierarchy looked similar to the image below. By clicking More and Less button Description field was toggled between short and long text.

View hierarchy

Since iOS 8 UITableView provides an easy way to automatically manage UITableViewCell height instead of manually calculating and providing it for each cell. It’s done by setting row height to automatic and providing estimated row height

tableView.rowHeight = UITableViewAutomaticDimensiontableView.estimatedRowHeight = 124

You just need to make sure you’ve set your constraints right, it means once e.g. your UILabel calculates its size properly it will be able to push its superview to desired size. It means you can’t e.g. set height constraint and eventually you should pin label from top to bottom. My case was very simple and I’ve just pinned UILabel to each side.

When it comes to animation it’s pretty straightforward once you don’t have to think about height. You just update text and animate size change. So code can look like this:

//cell
@IBAction func buttonMoreTouched(_ sender: UIButton) {
labelDescription.text = longText delegate?.contentDidChange(cell: self)}//delegate
extension TableViewController: CellDelegate {
func contentDidChange(cell: Cell) { UIView.animate(withDuration: 1) { self.tableView.beginUpdates() self.tableView.endUpdates() } }}

The outcome is working but it has some flaws.

Text changes instantaneously and whole table animates. However text is centered vertically which, in my case, wasn’t intended. I wanted to achieve something like “reveal more” behavior.

It turns out UIView has contentMode property which manages how it behaves when bounds change. In terms of UILabel we can treat it as an anchor for text while label gets resized. Changing it can be done directly in Interface Builder and desired value is “Top Left”:

Animation itself is exactly what I wanted to achieve. In this case I’m changing text to something totally different but if we had a short and long version of the same text then change would be impossible to even notice.

There is one glitch if you take a closer look at bottom cell. Once Less button is touched and content animates to top, new cell is rendered at the bottom but it reveals its content in the opposite direction: from top to bottom which doesn’t look nice.

It turns out the problem lays in UIView.animate which is not needed to animate content size change. All we have to do in delegate is:

func contentDidChange(cell: Cell) {    self.tableView.beginUpdates()    self.tableView.endUpdates()}

and it works beautifully!

Summary:

For automatically resizing UITableViewCell animation remember about:

  • settting height to UITableViewAutomaticDimension
  • providing default value of estimatedRowHeight
  • UIView contentMode property to anchor your content
  • beginUpdates and endUpdates don’t need to be placed inside UIView.animate block

If you want to play with code yourself the repository is here: https://github.com/burczyk/UITableViewCellAnimation

Feel free to follow me on Twitter as well https://twitter.com/KamilBurczyk and let me know if you have more tips about animating complicated Auto Layout views.

--

--

Kamil Burczyk
Grand Parade

Head of Engineering at William Hill, fitness and technology geek, Apple fan