我正在关注使用具有动态高度的UITableViewCell的thread的答案。这是link to the great GitHub solution for iOS7。
该示例在iOS7中适用于我,但是当我在iOS6中运行时,第一个单元格无法正确包装。
只有在我滚动屏幕的单元格并重新打开之后,包装看起来才正确。
这是我的代码,我做的任何更改都有以下注释,因此可以在iOS6中运行
// *** Added/Removed for iOS6
表格视图单元格
#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
}
表视图控制器
#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
任何想法是怎么回事?我很欣赏任何见解。
答案 0 :(得分:1)
根据@Wain的建议,我尝试将所有代码从heightForRowAtIndexPath
移动到cellForRowAtIndexPath
,这很有效。我想我需要设置cell.bodyLabel.preferredMaxLayoutWidth = CGRectGetWidth(cell.bodyLabel.frame)
。
我将所有代码移动到'cellForRowAtIndexPath'并让'heightForRowAtIndexPath'调用它来获得现在的高度。现在我不确定为什么它在iOS7而不是iOS6中都很好,但我还在搞清楚这些自动布局的东西。
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
[cell updateFonts];
NSDictionary *dataSourceItem = [self.model.dataSource objectAtIndex:indexPath.row];
cell.titleLabel2.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];
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
RJTableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
CGFloat height = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height;
return height;
}
答案 1 :(得分:0)
对于来自此页面的其他人,“使用你的面包”有几篇关于自动布局+ UITableViewCell
的文章。
他的代码展示了如何使用原型单元来计算高度,而不是每次都要求高度。这将导致更快的代码。
通过覆盖layoutSubviews
来设置preferredMaxLayoutWidth
,这意味着您无需在控制器中执行此操作。
- (void)layoutSubviews
{
[super layoutSubviews];
[self.contentView layoutIfNeeded];
self.lineLabel.preferredMaxLayoutWidth = CGRectGetWidth(self.lineLabel.frame);
}
[self.contentView layoutIfNeeded]
对于在首次加载时获得正确的布局也很重要。