iOS

Understanding Self Sizing Cells and Dynamic Type in iOS 8


In iOS 8, Apple introduces a new feature for UITableView known as Self Sizing Cells. To me, this is seriously one of the most exciting features for the new SDK. Prior to iOS 8, if you want to display dynamic content in table view with variable height, you would need to calculate the row height manually. Now with iOS 8, Self Sizing Cell provides a solution for displaying dynamic content. In brief, here are what you need to do when using self sizing cells:

  • Define auto layout constraints for your prototype cell
  • Specify the estimatedRowHeight of your table view
  • Set the rowHeight of your table view to UITableViewAutomaticDimension

If we express the last two points in code, it looks like this:

With just two lines of code, you instruct the table view to calculate the cell’s size matching its content and render it dynamically. This self sizing cell feature should save you tons of code and time. You’re gonna love it.

Building a Simple Demo Using Self Sizing Cell

There is no better way to learn a new feature than using it. We’ll develop a simple demo app to demonstrate self sizing cell. We’ll start with a project template. It’s just a simple table-based app showing a list of hotels. The prototype cell contains two one-line text labels for both name and address. If you download the project and run it, you’ll have an app like below:

Table View App with Truncated Text

As you can see, due to fixed row height, some of the hotel addresses are truncated. You may have faced the same issue when developing table-based apps. In the past, you may simply reduce the font size or increase the number of lines to fix the issue. Starting from iOS 8, all you need to do is to use Self Sizing Cells and the cell content can be displayed properly, regardless of content length.

Adding Auto Layout Constraints

You may hate Auto Layout and avoid using it. However, without auto layout, self sizing cells won’t work as it relies on the constraints to determine the proper row height. In fact, table view calls systemLayoutSizeFittingSize on your cell and that returns the size of the cell based on the layout constraints.

If this is the first time you work with Auto Layout, I recommend you to check out our Auto Layout Introduction before moving on.

For the project template, I haven’t defined any auto layout constraints for the prototype cell. So let’s add a few constraints for the cell first. For the name label, click the Pin button of the auto layout menu and add four spacing constraints.

Auto Layout Prototype Cell

For the address label, add further three spacing constraints for the left/right/bottom side.

Auto Layout Prototype Cell

If you have configured the constraints correctly, they should look something like below:

Self Sizing Cell - Auto Layout
Self Sizing Cell - Auto Layout

Setting Estimated Row Height

With the auto layout configured, the rest is to add the following code in the viewDidLoad method of the ViewController:

The first line of code sets the estimated row height of the cell, which is the height of the existing prototype cell. The second line changes the rowHeight property to UITableViewAutomaticDimension, which is the default row height in iOS 8. In other words, you tell table view to figure out the cell size based on other information.

If you test the app, the cell is still not resized. The reason is that both name and address labels are set to 1-line. So set the number of lines to zero and let the label grow automatically.

Self Sizing Cell - Number of Line

Now compile and run the app again. The table view cells are resized according to the content.

Self Sizing Cell Demo

A Bug?!

I’m not sure if it is a bug or not. But the problem was also mentioned by UseYourLoaf. When the table view is first displayed, you may find some of the cells are not sized properly. But when you scroll the table view, the new cells are displayed with correct row height. To workaround this issue, you can force a reload after the view appears:

Dynamic Type

Self Sizing Cell is particularly useful to support Dynamic Type. You may not have heard of Dynamic Type but you probably see the following screen in Settings:

Dynamic Type Settings

Dynamic Type was introduced in iOS 7. It allows users to customise the text size to fit their own needs. However, only apps that adopt Dynamic Type respond to the text change. I believe only a fraction of third-party apps have adopted the feature.

Starting from iOS 8, Apple wants to encourage developers to adopt Dynamic Type. As mentioned in the WWDC session, all of the system applications have adopted Dynamic Type and the built-in labels have dynamic fonts on them automatically in iOS 8. As the user changes the text size, those labels are going to change size.

Further, the introduction of Self Sizing Cell is a way to facilitate Dynamic Type adoption. It saves you tons of code from developing your own solution to adjust the row height. Once the cell is self-sized, it is very straightforward to adopt Dynamic Type.

In the demo project, you just need to change the font from a custom font of fixed size to a preferred font for text style (e.g. headline, body, etc). That’s it. When you run the app, it adapts to the text size change.

Dynamic Type Demo

Summary

In this tutorial, I have walked you through the basics of Self Sizing Cells and Dynamic Type. You’re encouraged to use the feature and update your app to adopt Dynamic Type. Self Sizing Cell is seriously one of my favorite features in iOS 8. With just a couple lines of code, you can easily fit dynamic content in a cell. This is truly fabulous. What do you think? Leave me comment and share your thought.

For your reference, you can download the complete project from here. Please note that I used Xcode 6 Beta 7 to create the project.

Tutorial
Introduction to the Accelerate Framework in Swift
iOS
Hello World! Build Your First iPhone App
Tutorial
Advanced ReplayKit: Integrating Live Broadcasting Into iOS Apps and Games
  • ohdowload

    ohdowloadohdowload

    Author Reply

    as always,great tutorial from appcoda. thank you


  • Chetan Kmr

    Chetan KmrChetan Kmr

    Author Reply

    Great tutorial !!

    tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) as CustomTableViewCell

    What does “as CustomTableViewCell” mean in swift ?


    • Simon Ng

      Simon NgSimon Ng

      Author Reply

      It means down casting. The tableView.dequeueReusableCellWithIdentifier(cellIdentifier, forIndexPath: indexPath) returns a UITableViewCell object. As a custom cell is used, it is casted to CustomTableViewCell using the “as” keyword.


  • Jan Kan

    Jan KanJan Kan

    Author Reply

    Thanks for the tut! Really fast and easy now. I have one question on Dynamic Type support. I have followed your instructions (changed the font to Headline and Body). Dynamic type works (changes in the size are reflected) only if I restart the app – any idea how to fix it?


    • Joshua Hensley

      You need to start listening for the “UIContentSizeCategoryDidChangeNotification” within your UICollectionViewController’s viewDidLoad(). And reload the collection view’s data when the notification is received.

      Inside viewDidLoad()
      NSNotificationCenter.defaultCenter().addObserver(self, selector: “onContentSizeChange:”, name: UIContentSizeCategoryDidChangeNotification, object: nil)

      Add onContentSizeChange function
      func onContentSizeChange(notification: NSNotification) {
      self.collectionView?.reloadData()
      }


      • Magesh

        MageshMagesh

        Author Reply

        Hi, could you please help me to fix this, I am very new to apps developing, it is not accepting collectionView?, so i changed that to tableView?. when change the dynamic fond size and open the app (without closing the simulator) i am getting an error : terminating with uncaught exception of type NSException.


  • Arkadi

    ArkadiArkadi

    Author Reply

    Question: when did apple release Xcode 6 beta7 ?

    “For your reference, you can download the complete project from here. Please note that I used Xcode 6 Beta 7 to create the project.” <<<< Developer.Apple.com only has beta 5….


    • Simon Ng

      Simon NgSimon Ng

      Author Reply

      Beta 7 was released earlier this week. You can download it here:

      https://developer.apple.com/swift/resources/


      • Arkadi

        ArkadiArkadi

        Author Reply

        LOL

        I found the source of my error, its still ios8 beta 5 but it’s xcode6 beta 7

        Usually they are the same but it looks like osx is in beta 7 right now.

        A bit strange then you think about it.


  • bbpan

    bbpanbbpan

    Author Reply

    Do you know how to make sure visible cells are properly resized before actually showing them?

    I found that if you pushed from one UITableViewController to another, which has auto sizing cells, you would see the cells resizing in action. Some cells would even stop resizing if you immediately start scrolling up or down the table view. Auto sizing doesn’t seem to work very well if it were not the first scene.


    • ChrisRicca

      ChrisRiccaChrisRicca

      Author Reply

      I’ve added a comment above, but I just used tableView:reloadSections within viewWillAppear and it works without the flicker


  • Josh Chen

    Josh ChenJosh Chen

    Author Reply

    Can you do one with custom cell?


  • Jesus

    JesusJesus

    Author Reply

    Hi, thanks for the tutorial, now it’s really easier to create cells with dynamic cells. I have a problem, I am using images in my table cells and it seems that this method doesn’t take in count images because it just adjust the height to the label size, what can I do?


  • ranjit kadam

    I want to know what will be the final height of the row, because I need to add some UI elements at the end if the row. So please tell me how it can be done.


  • Stefanie

    StefanieStefanie

    Author Reply

    This doesn’t work with statics cells type. How can I fix this?


  • ChrisRicca

    ChrisRiccaChrisRicca

    Author Reply

    Instead of using viewDidAppear (which allowed a flicker when the cells re-rendered), I used tableView reloadSections: within viewWillAppear and it worked without that flicker


    • Nuno

      NunoNuno

      Author Reply

      Perrrfect! Sad that we need this workaround. But hey, it worked great for me 🙂 And no flicker! Thank you.


      • Nuno

        NunoNuno

        Author Reply

        I suggest this put this in an extension (UITableViewControllers only): self.tableView.reloadSections(NSIndexSet(indexesInRange: NSMakeRange(0, self.tableView.numberOfSections())), withRowAnimation: .None)


        • tg6

          tg6tg6

          Author Reply

          Hi, I used


  • gg

    gggg

    Author Reply

    Hi, thanks for he tutorial but i have a question.

    How can you disable the scroll to top event when you use reloadData() ?

    Its only appear when you use dynamic cell height.


    • Sven

      SvenSven

      Author Reply

      Before you call reloadData(), remember the top visible row, and after reloadData() scroll programmatically to that row without animation.


  • Yannick

    YannickYannick

    Author Reply

    great tutorial!
    is it possible to have two labels with dynamic text length and dynamic height. With your solution only one label resizes in my project. Any ideas?


  • pradeep

    pradeeppradeep

    Author Reply

    Hi Simon, Not sure if this is bug or not. After adding prototype cell – style as ‘subtitle’ and accessory as ‘detail disclosure’, detail disclosure is not visible in iphone 4s,5 and partially visible in iphone 6 simulator…I’m using xcode 6.0.1 and layout as Compact width | Any height…It would be great if you can test this and any solution for this…Thanks in advance


  • Lorenzo

    LorenzoLorenzo

    Author Reply

    I also noticed a flicker with the bug workaround provided. What I did instead was reload the table in viewDidLayoutSubviews but you need to create a boolean to ensure this only happens once, otherwise it creates an infinite loop.


    • Travis

      TravisTravis

      Author Reply

      ^^^ great tip! Thanks.


  • Mobile application training in

    Thanks for your tutorial …


  • Parul

    ParulParul

    Author Reply

    Thanks 🙂 Great Tutorial


  • rem2

    rem2rem2

    Author Reply

    – (void)viewDidLoad {
    [self.tableView layoutIfNeeded]; }


  • deckikwok

    deckikwokdeckikwok

    Author Reply

    not sure if it has been sorted out. I was having issues with the ios ‘bug’ where some of the cells were not resized properly. i’ve sorted mine by giving my uiview and parent view the same content hugging priority so the child view will grow to fill the parent’s width.


  • Ranjit

    RanjitRanjit

    Author Reply

    Firstly thanks for the tutorial, but when I have more than 7-8 rows and when I scroll the table and try to update row, by using reloadRowsAtIndexPath, then the table bounces back to top. Can anybody help me out with this


  • Dipesh Upadhyaya Atrey

    the tutorial is excellent but if user inputs the new line without completing the text its working methods gets failed.
    eg:

    This
    is

    for
    my
    beautiful
    girlfriend.

    the view for the above text is looking perfect.


  • xh

    xhxh

    Author Reply

    lack removing ” tableView:heightForRowAtIndexPath:” delegate method step


  • shigasuresh

    Nice Tutorial:) Is it possible in two labels to dispaly with dynamic cell sizing in tableview?????


  • Spooky Mormon Hell Dream

    I see this self-sizing behavior works fine with standard UITableViewCells of type UITableViewCellStyleDefault, but not with UITableViewCellStyleSubtitle. Is that a known issue or am I missing something? I would rather use system-provided controls if possible for most of my of my UI.


  • Anderson Silva

    Thank you, I couldn’t do it without this tutorial!


  • rickw

    rickwrickw

    Author Reply

    Great tutorial, I’ve found instead of reloaded the tableView add this to your cell subclass

    override class func requiresConstraintBasedLayout() -> Bool {
    return true
    }


  • shvetapuri

    shvetapurishvetapuri

    Author Reply

    Thanks for the tutorial. This works on my static tableview cell initially but after returning from a modal segue with new data, the table cell does not resize. I have tried reload in viewwillappear, and when I add the new data to the cell. I also have :

    self.tableView.estimatedRowHeight=44.0;

    self.tableView.rowHeight=UITableViewAutomaticDimension;

    self.cellStartLeft.textLabel.numberOfLines=0;

    what else can I try?


  • saikiran k

    saikiran ksaikiran k

    Author Reply

    great tutorial, earlier i used to calculate height in heightforrowAtIndexPath even with auto layout, i did not know about this approach. this saved lot of time.


  • Huan

    HuanHuan

    Author Reply

    Thanks!


  • Vinicius Miranda

    GREATTTTsss!!!! tks


  • Nitesh Kumar

    Hey , I got the solution for
    A Bug?!

    Since constraints are set before values populate in cell, if we call tablecell.layoutIfNeeded() In

    cellForRowAtIndexPath That problem will be resolved .


  • kaur

    kaurkaur

    Author Reply

    This is a very helpful tutorial and works beautifully. What can I do to have it work for iOS 7 ?


  • lemotz

    lemotzlemotz

    Author Reply

    Hi there, I ran your codes as is, however, my scroll bar reaches the end of screen and last few rows are not visible. I appreciate any suggestions ? Is there something wrong with my setup ?


  • Mauro

    MauroMauro

    Author Reply

    Great solution, i looking for about 2 weeks, thanks. Mauro


  • Shachar Silbert

    tableView.estimatedRowHeight = 44.0 Is probably what is creating the “BUG” of the stuck size on load, from the doc:
    “Using estimation allows you to defer some of the cost of geometry calculation from load time to scrolling time.”


  • Tola Soy

    Tola SoyTola Soy

    Author Reply

    Hi, i have some question about cell dynamic height. if one cell has 5 label and some label dynamic height. So cell hight can resize depend on height of label or not?


  • Omar O. Hashim

    Thank you so much! Really clear and concise 😀


  • utkarsh kumar

    Amazing Tutorial! Saved me SO MUCH TIME


  • Anna Shatrova

    Thank u so much!!! really help in my work!!! *applauds*


  • Shripada Hebbar

    Swift 4 version of the finished code is here:
    https://www.dropbox.com/s/om4rkpmr9gdqboy/SelfSizingDemo.zip?dl=0


Shares