Question

I'm working on a simple app to display items in a table view. If I return an ordinary UITableViewCell object from tableView:cellForRowAtIndexPath:

static NSString *cellIdentifier = @"EmailCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:
    cellIdentifier];

if (!cell) {
    cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault 
        reuseIdentifier:@"EmailCell"];
}

cell.textLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];

... then the interaction with Dynamic Text works as expected; if the user goes to Settings | General | Text Size, changes the slider value and then returns to my app, all of the visible cells immediately update themselves to use the new font size.

If, however, I return a custom subclass of UITableViewCell, where the XIB contains a UILabel that is set to use a Text Style instead of a System Font, then the Dynamic Text does not work properly. Here is the code I'm using to assign the XIB to the table in viewDidLoad:

[self.table registerNib:[UINib nibWithNibName:@"EmailCell"
                                           bundle:[NSBundle mainBundle]]
     forCellReuseIdentifier:@"EmailCell"];

and then this code in tableView:cellForRowAtIndexPath:

static NSString *cellIdentifier = @"EmailCell";
EmailCell *cell = (EmailCell *)[tableView 
    dequeueReusableCellWithIdentifier:cellIdentifier];

When I first run the app, the visible cells appear with a text size that matches the user's selected preferred text size. However, if I then go to settings and change that size and then go back to my app, all of the visible cells remain with the previous text size. If I then scroll up, I will see two cells that show the new (correct) text size but the rest are still the old size. If I stop and restart the app, all cells now appear with the new (correct) text size.

It seems apparent to me that the tableview is keeping the previously-sized cells in the queue and not automatically updating their font size in response to the user's change of preferred text size. But I'm not understanding why the tableview does make this change automatically when the queue contains ordinary non-subclassed UITableViewCell instances. Is there any way I can get this to work without restarting the app (or without recreating the UITableView instance, thereby emptying the queue)? Is there any way to programmatically (and legally) clear this queue?

Edit: in case anyone's interested in this problem, my drop-in fix for this was to write a general utility method that makes a new tableview, copies over all the relevant properties from the original tableview (included registered cell classes) and then swaps the new one for the old one. Since this is a new table, it generates all-new instances of the queued cells which incorporate the new text size.

Was it helpful?

Solution

This is now handled for you in iOS 10.

http://useyourloaf.com/blog/auto-adjusting-fonts-for-dynamic-type/

Set adjustsFontForContentSizeCategory to YES / true on your label and it'll resize itself automatically when the text size preference changes.

OTHER TIPS

Based on what you described, it would seem that you simply want to reload the table anytime the view comes back on screen after the user has backgrounded it. To achieve this the way I think you want, you need to add the following in your init method for your tableView - it will tell your tableView to reload the cells properly whenever the app is about to enter the foreground:

[[NSNotificationCenter defaultCenter] addObserver:self.tableView selector:@selector(reloadData) name:UIApplicationWillEnterForegroundNotification object:nil];

This way, if the user comes back to the view by opening the app after going to the phone's settings, your tableView should reload and the changes (if any were made) should properly be reflected.

You can see a quick video of the result I tested here:

https://www.dropbox.com/s/pvjuiyofydnxnvd/textsize.mov

EDIT:

Like you said in a previous comment, it would seem like it's something wrong with your nib implementation. The only difference is where/how you update the label property. In the custom cell, I created a label property and a font property, and added the label to the cell in init, and in layoutSubviews I overrode the font. Here's the code:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    LabelCell *cell = [tableView dequeueReusableCellWithIdentifier:@"LabelCell"];

    if (cell == nil) {
        cell = [[LabelCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"LabelCell"];
    }

    cell.myLabel.text = _items[indexPath.row];
    cell.myFont = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline];

    return cell;
}

And in the cell itself:

- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];

    self.myLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 0, self.contentView.frame.size.width - 20, 34)];
    self.myLabel.backgroundColor = [UIColor greenColor];
    [self.contentView addSubview:self.myLabel];

    return self;
}

- (void)layoutSubviews {
    [super layoutSubviews];

    self.myLabel.font = self.myFont;
}

And here is the same result using custom cells with labels:

https://www.dropbox.com/s/ow2zkb6j9yq2c3m/labelcells.mov

Regarding "clearing the queue", the cells don't get queued up until they are juuuust about to be shown on screen, you can see this by logging a counter value right after you dequeue cell with identifier. If there are 10 cells on screen right now, it only dequeues 10 cells. This is the reason why you use the code if (!cell) {do stuff here that's common for all cells} and then you do things that are specific to each cell afterwards, and why this code works even if you were to assume that reloadData didn't "clear the queue", which I'm not convinced it wouldn't anyway after reading through the UITableView docs.

My drop-in fix for this was to write a general utility method that makes a new tableview, copies over all the relevant properties from the original tableview (included registered cell classes) and then swaps the new one for the old one. Since this is a new table, it generates all-new instances of the queued cells which incorporate the new text size.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top