vikingfo04 vikingfo04 - 3 months ago 23
Swift Question

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!

Answer

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.