I am following the answer from this thread about using a UITableViewCell with a dynamic height. Here is the link to the great GitHub solution for iOS7.
The example works in for me in iOS7, but when I run it in iOS6 the first cell(s) do not wrap correctly.
It's only after I scroll the cell of the screen and back on does the wrapping look correct.
Here is my code, with the following comment by any changes I made so it could run in iOS6
// *** Added/Removed for iOS6
The table view cell
#import "RJTableViewCell.h"
#define kLabelHorizontalInsets 20.0f
@interface RJTableViewCell ()
@property (nonatomic, assign) BOOL didSetupConstraints;
@end
@implementation RJTableViewCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self.titleLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.titleLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[self.titleLabel setNumberOfLines:1];
[self.titleLabel setTextAlignment:NSTextAlignmentLeft];
[self.titleLabel setTextColor:[UIColor blackColor]];
[self.titleLabel setBackgroundColor:[UIColor clearColor]];
self.bodyLabel = [[UILabel alloc] initWithFrame:CGRectZero];
[self.bodyLabel setTranslatesAutoresizingMaskIntoConstraints:NO];
[self.bodyLabel setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
[self.bodyLabel setLineBreakMode:NSLineBreakByTruncatingTail];
[self.bodyLabel setNumberOfLines:0];
[self.bodyLabel setTextAlignment:NSTextAlignmentLeft];
[self.bodyLabel setTextColor:[UIColor darkGrayColor]];
[self.bodyLabel setBackgroundColor:[UIColor clearColor]];
[self.contentView addSubview:self.titleLabel];
[self.contentView addSubview:self.bodyLabel];
[self updateFonts];
}
return self;
}
- (void)updateConstraints
{
[super updateConstraints];
if (self.didSetupConstraints) return;
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.titleLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:kLabelHorizontalInsets]];
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.titleLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:(kLabelHorizontalInsets / 2)]];
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.titleLabel
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:-kLabelHorizontalInsets]];
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.bodyLabel
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:kLabelHorizontalInsets]];
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.bodyLabel
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.titleLabel
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:(kLabelHorizontalInsets / 4)]];
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.bodyLabel
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:-kLabelHorizontalInsets]];
[self.contentView addConstraint:[NSLayoutConstraint
constraintWithItem:self.bodyLabel
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.contentView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:-(kLabelHorizontalInsets / 2)]];
self.didSetupConstraints = YES;
}
- (void)updateFonts
{
self.titleLabel2.font = [UIFont systemFontOfSize:16.0f]; // *** Added for iO6
self.bodyLabel.font = [UIFont systemFontOfSize:12.0f]; // *** Added for iO6
// self.titleLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleHeadline]; // *** Removed for iO6
// self.bodyLabel.font = [UIFont preferredFontForTextStyle:UIFontTextStyleCaption2]; // *** Removed for iO6
}
The table view controller
#import "RJTableViewController.h"
#import "RJModel.h"
#import "RJTableViewCell.h"
static NSString *CellIdentifier = @"CellIdentifier";
@interface RJTableViewController ()
@property (strong, nonatomic) RJModel *model;
// This property is used to work around the constraint exception that is thrown if the
// estimated row height for an inserted row is greater than the actual height for that row.
// See: https://github.com/caoimghgin/TableViewCellWithAutoLayout/issues/6
@property (assign, nonatomic) BOOL isInsertingRow;
@end
@implementation RJTableViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
self.title = @"Table View Controller";
self.model = [[RJModel alloc] init];
[self.model populateDataSource];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.tableView registerClass:[RJTableViewCell class] forCellReuseIdentifier:CellIdentifier];
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash target:self action:@selector(clear:)];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addRow:)];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableView reloadData]; // *** Added for iOS6
// *** Removed for iOS6
// [[NSNotificationCenter defaultCenter] addObserver:self
// selector:@selector(contentSizeCategoryChanged:)
// name:UIContentSizeCategoryDidChangeNotification
// object:nil];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.tableView reloadData]; // *** Added for iOS6
// *** Removed for iOS6
// [[NSNotificationCenter defaultCenter] removeObserver:self
// name:UIContentSizeCategoryDidChangeNotification
// object:nil];
}
- (void)contentSizeCategoryChanged:(NSNotification *)notification
{
[self.tableView reloadData];
}
- (void)clear:(id)sender
{
NSMutableArray *rowsToDelete = [NSMutableArray new];
for (NSUInteger i = 0; i < [self.model.dataSource count]; i++) {
[rowsToDelete addObject:[NSIndexPath indexPathForRow:i inSection:0]];
}
self.model = [[RJModel alloc] init];
[self.tableView deleteRowsAtIndexPaths:rowsToDelete withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView reloadData];
}
- (void)addRow:(id)sender
{
[self.model addSingleItemToDataSource];
self.isInsertingRow = YES;
NSIndexPath *lastIndexPath = [NSIndexPath indexPathForRow:[self.model.dataSource count] - 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:@[lastIndexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
self.isInsertingRow = NO;
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.model.dataSource count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
[cell updateFonts];
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.titleLabel.text = [dataSourceItem valueForKey:@"title"];
cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];
// Make sure the constraints have been added to this cell, since it may have just been created from scratch
[cell setNeedsUpdateConstraints];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell updateFonts];
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.titleLabel.text = [dataSourceItem valueForKey:@"title"];
cell.bodyLabel.text = [dataSourceItem valueForKey:@"body"];
[cell setNeedsUpdateConstraints];
[cell updateConstraintsIfNeeded];
// Do the initial layout pass of the cell's contentView & subviews
[cell.contentView setNeedsLayout];
[cell.contentView layoutIfNeeded];
// Since we have multi-line labels, set the preferredMaxLayoutWidth now that their width has been determined,
// and then do a second layout pass so they can take on the correct height
cell.bodyLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.bodyLabel.frame);
[cell.contentView layoutIfNeeded];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (self.isInsertingRow) {
// A constraint exception will be thrown if the estimated row height for an inserted row is greater
// than the actual height for that row. In order to work around this, we return the actual height
// for the the row when inserting into the table view.
// See: https://github.com/caoimghgin/TableViewCellWithAutoLayout/issues/6
return [self tableView:tableView heightForRowAtIndexPath:indexPath];
} else {
return 500.0f;
}
}
@end
Here is a before and after of what I'm seeing if that is useful.
Any ideas what is going on? I appreciate any insight.