Search code examples
iosswiftuitableviewios9

Dynamic Type and Self-Sizing Cells with Static Table


I have a typical master-detail app that allows the user to browse a scrolling list of objects, and then drill to detail for any particular object with a push segue. The scrolling master list is a UITableView built with prototype cells, and the detail scene is a static UITableView with a fixed number of sections and cells.

I would like to implement Dynamic Type and Self-Sizing Cells in my app so that the user can change the base font size. So far, I have been successful making self-sizing cells with the scrolling list of prototype cells: by using Auto Layout, setting number of lines in each label to 0, and setting tableView.rowHeight = UITableViewAutomaticDimension, the height of each prototype cell grows or shrinks to accommodate the size of the text within.

But I can't achieve the same effect in my static table view. Whether I use custom cells or built-in cell types, the font grows/shrinks but the cell height does not.

So my question is actually two questions: 1) is it possible to implement self-sizing cells in static table views, like I've done with my prototype table view? and 2) if the answer to the first question is no, how do I write code that will measure the height of a label in a static table view cell and adjust the cell height appropriately?

Thank you!


Solution

  • I'm grateful for the answers provided to the question I posted yesterday. Unfortunately (and likely because of my own inexperience as an iOS programmer) I was not able to make the systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) approach work. After some trial and error, however, I found a different method that seems to work:

    import UIKit
    
    class MasterTVC: UITableViewController {
        @IBOutlet weak var staticCustomCellLabel: UILabel!
    
        //viewDidLoad
        override func viewDidLoad() {
            super.viewDidLoad()
    
            self.tableView.estimatedRowHeight = 44.0
    
            staticCustomCellLabel.text = "This is the text for the static custom cell label; This is the text for the static custom cell label; This is the text for the static custom cell label"
    
            //Register handleDynamicTypeChange in observer: self
            NSNotificationCenter.defaultCenter().addObserver(self, selector: "handleDynamicTypeChange:", name: UIContentSizeCategoryDidChangeNotification, object: nil)
        }
    
        //deinit
        deinit {
            NSNotificationCenter.defaultCenter().removeObserver(self)
        }
    
        //handleDynamicTypeChange
        //called when user changes text size in Settings > General > Accessibility > Larger Text
        //or Settings > Display & Brightness > Text Size
        func handleDynamicTypeChange(notification: NSNotification) {
            staticCustomCellLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody)
    
            self.tableView.reloadData()
        }
    
        //tableView:heightForRowAtIndexPath
        override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
            return UITableViewAutomaticDimension
        }
    }
    

    On the Storyboard side of this, the setup begins with a single Table View Controller with the following properties:

    • Class: MasterTVC (my custom class);
    • designated the initial view controller;
    • Content: Static Cells;
    • Style: Grouped
    • Sections: 1.

    Section-1:

    • Rows: 1.

    Table View Cell:

    • Style: Custom (using Basic here causes the label to disappear when changing text size in Settings);
    • Containing a UILabel.

    The UILabel is further configured as:

    • Font: Body (a Dynamic Type style);
    • Lines: 0;
    • Pinned on all four sides to the top, bottom, left, and right edges of the content view (I used the respective constraints 8, 8, 15, 15);
    • with an @IBOutlet in the custom class code.

    This worked for me designing for iOS 9 in Xcode 7 and Swift 2 with Auto Layout enabled. The interesting thing is that if you strip away the NSNotificationCenter code that is used to respond immediately to changes in text size, the self-sizing cells code is basically two lines: setting estimatedRowHeight in viewDidLoad, and returning UITableViewAutomaticDimension from tableView:heightForRowAtIndexPath.

    Based on these results, I believe the answers to my original question are: 1) yes; and 2) see 1.