UITableViewCell text disappears on dynamic font size change

None of the the standard UITableViewCell styles support "Dynamic Type". The Cells are resized but the label's text dissapears.


If I create my own custom UITableViewCell and drag out my own labels, their text doesn't dissapear when the "Text Size" is changed.

Replies

It appears that the UITableView listens for UIContentSizeCategoryDidChangeNotification and when it comes to the the default cell styles, it recreates its internal labels, which is complete madness.


It doens't respect if any of those labels has a Custom class specified, nor does it respect if the UITableView is showing static cells or not (in my case I'm also using bindings so the the bindings become invalid because the labels I'm holding references to are no longer the visible ones).


I have a workaround for when using the default styles. I remove the tableview as a observer from the NSNotificationCenter and listen to the event myself, once the event fires, I call the TableView.ReloadData(). Since the TableView didn't recreate the labels, my bindings are still valid and everything gets updated correctly.


The scenario when using static custom cells is handled by just resetting the text, if any, when the event fires. I don't remove the UITableView because I haven't been able to reproduce the correct row height.

This is a terrible hackish workaround that will probably bite me later but somehow it fixed all my Dynamic Text issues (iOS 11). As long as iOS doesn't use UIContentSizeCategoryDidChangeNotification for anything else on UITableView, this workaround shouldn't break anything.


For anybody that wants to add this to their table view collection subclass (Swift 4, iOS 11):

override func viewDidLoad() {
  super.viewDidLoad()
  NotificationCenter.default.removeObserver(tableView!, name: .UIContentSizeCategoryDidChange, object: nil)
}

(or add line 3 to your overriding implementation of viewDidLoad())


I'm performing manual font changes in prepareForReuse() of the custom table view cell class. By reloading the table view, the changes are applied to the cells. Add this to your view controller subclass to reload your cells (or do other work):

override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
  super.traitCollectionDidChange(previousTraitCollection)
  if self.traitCollection.preferredContentSizeCategory != previousTraitCollection?.preferredContentSizeCategory {
    tableView?.reloadData()
  }
}


Thank you very much — you spared me hours of work! 🙂

It seems that UIContentSizeCategoryDidChangeNotification is never emitted when font size changed. By the way, traitCollectionDidChange method is not called either.


- (void)viewDidLoad {

[super viewDidLoad];

[[NSNotificationCenter defaultCenter] removeObserver:self.tableView name:UIContentSizeCategoryDidChangeNotification object:nil];


[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contentSizeDidChanged:) name:UIContentSizeCategoryDidChangeNotification object:nil];

}


- (void) contentSizeDidChanged:(NSNotification *) notification {

NSLog(@"Content size changed!");

}