问题
I have been trying to get this tutorial dynamic-cell-height to work in ios8 for days now and can't figure out what is going on. It works in ios7 on the iphone and it works in both ios7 & ios8 on the iPAD but it doesn't work on any the iphone on ios8.
I think the problem lies in how and when the labels are being created within the cell.
I have the following code in the controller:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.dbManager = [[DBManager alloc] initWithDatabaseFilename:@"tomhaisdb.sql"];
[self loadData];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self deselectAllRows];
}
-(void)deselectAllRows{
for (NSIndexPath * indexPath in [self.tableView indexPathsForSelectedRows]) {
[self.tableView deselectRowAtIndexPath:indexPath animated:NO];
}
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)loadData {
NSString *query = @"select * from favourites";
if (self.favourites != nil) {
self.favourites = nil;
}
self.favourites = [[NSArray alloc] initWithArray:[self.dbManager loadDataFromDB:query]];
/* [self reloadDataWithCompletions:^{
self.tableView.backgroundColor = [UIColor colorWithRed:28.0f/255.0f green:30.0f/255.0f blue:35.0f/255.0f alpha:1];
}];*/
[self reloadTableViewContent];
}
- (void)reloadTableViewContent {
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
[self.tableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
});
}
/*-(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
return 1;
}*/
#pragma mark - UITableViewDataSource
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
NSLog(@"Number of rows: %d", self.favourites.count);
return self.favourites.count;
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
return [self basicCellAtIndexPath:indexPath];
}
-(favouritedCell *)basicCellAtIndexPath:(NSIndexPath *)indexPath {
favouritedCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"favouriteCell" forIndexPath:indexPath];
[self configureBasicCell:cell atIndexPath:indexPath];
return cell;
}
-(void)configureBasicCell:(favouritedCell *)cell atIndexPath:(NSIndexPath *)indexPath{
NSInteger indexOfTomhaisText = [self.dbManager.arrColumnNames indexOfObject:@"tomhaisText"];
NSString *tomhaisText = [[self.favourites objectAtIndex:indexPath.row] objectAtIndex:indexOfTomhaisText];
[self setTomhaisForCell:cell item:tomhaisText];
[self setAnswerForCell:cell item:tomhaisText]; // change this later
}
-(void)setTomhaisForCell:(favouritedCell *)cell item:(NSString *)item{
[cell.favouriteText setText:item];
}
-(void)setAnswerForCell:(favouritedCell *)cell item:(NSString *)item{
[cell.answer setText:item];
}
#pragma mark - UITableViewDelegate
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
/* if ([[[UIDevice currentDevice]systemVersion]floatValue] >= 8.0) {
return UITableViewAutomaticDimension;
}
else{*/
return [self heightForFavouriteCellAtIndexPath:indexPath];
/*}*/
}
-(CGFloat)heightForFavouriteCellAtIndexPath:(NSIndexPath *)indexPath{
static favouritedCell *sizingCell = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sizingCell = [self.tableView dequeueReusableCellWithIdentifier:@"favouriteCell"];
});
[self configureBasicCell:sizingCell atIndexPath:indexPath];
return [self calculateHeightForConfiguredSizingCell:sizingCell];
}
-(CGFloat)calculateHeightForConfiguredSizingCell:(UITableViewCell *)sizingCell{
sizingCell.bounds = CGRectMake(0.0f, 0.0f, CGRectGetWidth(self.tableView.frame), CGRectGetHeight(sizingCell.bounds));
NSLog(@"Bounds before Layout %@", NSStringFromCGRect(sizingCell.bounds));
NSLog(@"Content View before Layout %@", NSStringFromCGRect(sizingCell.contentView.bounds));
[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];
CGSize size = [sizingCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
NSLog(@"Bounds after layout %@", NSStringFromCGRect(sizingCell.bounds));
NSLog(@"Content View before Layout %@", NSStringFromCGRect(sizingCell.contentView.bounds));
return size.height + 1.0f;
}
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 155.0f;
}
And in a custom Label the cell uses I have the following:
@implementation favouriteLabel
- (void)setBounds:(CGRect)bounds {
[super setBounds:bounds];
// If this is a multiline label, need to make sure
// preferredMaxLayoutWidth always matches the frame width
// (i.e. orientation change can mess this up)
if (self.numberOfLines == 0 && bounds.size.width != self.preferredMaxLayoutWidth) {
self.preferredMaxLayoutWidth = self.bounds.size.width;
NSLog(@"Label Bounds before update constraints %@", NSStringFromCGRect(self.bounds));
[self setNeedsUpdateConstraints];
NSLog(@"Label Bounds after update constraints %@", NSStringFromCGRect(self.bounds));
}
}
@end
The reason I think my problem lies with when the labels get created is because in ios 7 I get output like this:
2015-06-01 20:07:10.563 Facts[63322:607] Label Bounds before update constraints {{0, 0}, {216, 2}}
2015-06-01 20:07:10.563 Facts[63322:607] Label Bounds after update constraints {{0, 0}, {216, 2}}
2015-06-01 20:07:10.563 Facts[63322:607] Label Bounds before update constraints {{0, 0}, {217, 40}}
2015-06-01 20:07:10.563 Facts[63322:607] Label Bounds after update constraints {{0, 0}, {217, 40}}
>2015-06-01 20:07:10.564 Facts[63322:607] Bounds after layout {{0, 0}, {256, 82}}
2015-06-01 20:07:10.564 Facts[63322:607] Content View before Layout {{0, 0}, {256, 82}}
2015-06-01 20:07:10.564 Facts[63322:607] Bounds before Layout {{0, 0}, {256, 82}}
2015-06-01 20:07:10.564 Facts[63322:607] Content View before Layout {{0, 0}, {256, 82}}
2015-06-01 20:07:10.565 Facts[63322:607] Bounds after layout {{0, 0}, {256, 82}}
2015-06-01 20:07:10.565 Facts[63322:607] Content View before Layout {{0, 0}, {256, 82}}
2015-06-01 20:07:10.569 Facts[63322:607] Label Bounds before update constraints {{0, 0}, {216, 74.5}}
2015-06-01 20:07:10.569 Facts[63322:607] Label Bounds after update constraints {{0, 0}, {216, 74.5}}
2015-06-01 20:07:10.569 Facts[63322:607] Label Bounds before update constraints {{0, 0}, {217, 40}}
2015-06-01 20:07:10.570 Facts[63322:607] Label Bounds after update constraints {{0, 0}, {217, 40}}
But in ios8 the output is different.
2015-06-01 20:18:06.049 Facts[63396:81689795] Bounds before Layout {{0, 0}, {256, 44}}
2015-06-01 20:18:06.049 Facts[63396:81689795] Content View before Layout {{0, 0}, {320, 44}}
2015-06-01 20:18:06.131 Facts[63396:81689795] Label Bounds before update constraints {{0, 0}, {216, 0}}
2015-06-01 20:18:06.131 Facts[63396:81689795] Label Bounds after update constraints {{0, 0}, {216, 0}}
2015-06-01 20:18:06.131 Facts[63396:81689795] Label Bounds before update constraints {{0, 0}, {217, 4.5}}
2015-06-01 20:18:06.131 Facts[63396:81689795] Label Bounds after update constraints {{0, 0}, {217, 4.5}}
In ios7 the label seems to be created first, then cell bounds, and then the label is resized again. But in ios8 we see the content view output first and only then do we see the output for the label.
I'm sorry I can't explain it any better. It's a bit of a mystery to me how ios makes it's tables so I'm really stuck as to why it works in ios7 and not in ios8
Any help most appreciated. I had already written this question up here: Dynamic Cell Height autolayout IOS But I think I threw in a red herring about autolayout on that question.
回答1:
The frame was misplaced for the Answer label. Since the label was not installed for anyXany, the warning wasn't visible in Interface Builder.
Because the constraints didn't equal the expected height, that stopped Auto Layout from properly solving the cell height for iOS 8.
Quick fix is to tick its Installed box for anyXany. You'll see the warning show up. Select the Answer label, select Editor->AutoLayout Issues->Update Frames, and you're good to go!
Update:
The reason why the labels show up initially, without needing to reload, is because the anyXany box is ticked. Apple sees there are constraints installed, and the initial height is correct without reload or scrolling.
When the box is not ticked, the constraints get added too late in the layout process for the label to have the right initial height.
I'd recommend leaving the cell's labels installed (for any size class), since the cell's constraints don't change, depending on traits.
(While the tableView constraints do change, the cell's constraints should not be conditional. If there is a cell, it will always have the same constraints, regardless of size class.)
来源:https://stackoverflow.com/questions/30581572/dynamic-cell-height-in-uitableview-with-autolayout