3

I'm using AutoLayout, and for some reason as soon as the Table View loads:

  • the first couple table view cells on screen aren't layed out correctly
  • but the table view cells off screen when scrolled to are layed out correctly
  • but when I scroll back up to the original table view cells that weren't laying out correctly, once they go off screen and then back on screen all of the sudden are layed out correctly

Any help would be appreciated, thanks!

cellForRowAtIndexPath:

if ([model isKindOfClass:[FRSS self]]) {
        FRSS *fDan = (FRSS *)model;
        // configure cell
        MRWebListTableViewCell  *api1Cell = [tableView dequeueReusableCellWithIdentifier:@"YourAPI1Cell"];

        // RSS
        NSString *title = [NSString stringWithFormat:@"%@", fDan.title];

        // Get string from XML
        NSString *dateString = [self timeSincePublished:fDan.pubDate];

        // Get description without tags
        NSString *description = [self removeHTMLTags:fDan.description];

        NSString *link = [NSString stringWithFormat:@"%@", fDan.link];

        api1Cell.labelHeadline.text = title;
        api1Cell.labelDescription.text = description;
        api1Cell.labelPublished.text = dateString;

        // Top Image View
        UIImageView *imv = [[UIImageView alloc]initWithFrame:CGRectMake(15, 20, 50, 50)];
        imv.image=[UIImage imageNamed:@"e_r.png"];
        [api1Cell.contentView addSubview:imv];

        return api1Cell;

UPDATE: Had a lot of problems with AutoLayout even after trying a bunch of different things.

This had a lot to do with heightForRowAtIndexPath. Ended up needing to manually set this by adding the function into ViewController code. Manually set it for any cells that were going to be way larger than a normal estimated cell would be (i.e. if it had any images in it).

Realinstomp
  • 532
  • 2
  • 13
  • 30

3 Answers3

4

It seems, there are still some defects in self-sizing UITableView cells.

Here is the workaround we are using. I don't know the exact underlying mechanism though, but this is the most simple hack we found.

@implemetation YourTableViewCell

- (void)setFrame:(CGRect)frame {
    if(frame.size.width != self.bounds.size.width) {
        [super setFrame:frame];
        self.contentView.bounds = CGRectMake(0, 0, frame.size.width, frame.size.height);
        [self.contentView layoutIfNeeded];
    }
    else {
        [super setFrame:frame];
    }
}

// .. any other methods

@end

If you cannot edit UITableViewCell subclass, try this instead in your UITableViewDataSource:

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

    // setup cell ...

    CGSize sysSize = [cell.contentView systemLayoutSizeFittingSize:CGSizeMake(tableView.bounds.size.width, CGFLOAT_MAX)];
    cell.contentView.bounds = CGRectMake(0,0, sysSize.width, sysSize.height);
    [cell.contentView layoutIfNeeded];
    return cell;
}

BTW, in your code, this is a problem.

    // Top Image View
    UIImageView *imv = [[UIImageView alloc]initWithFrame:CGRectMake(15, 20, 50, 50)];
    imv.image=[UIImage imageNamed:@"e_r.png"];
    [api1Cell.contentView addSubview:imv];

You should not create/addSubview a View in tableView:cellForRowAtIndexPath:. You already have UIImageView in your NIB, right? use it like:

api1Cell.topImageView.image = [UIImage imageNamed:@"e_r.png"];

If your image is dynamic, the easiest solution is to use library like SDWebImage

#import <SDWebImage/UIImageView+WebCache.h>

...

    if ([model isKindOfClass:[FRSS self]]) {
        FRSS *fDan = (FRSS *)model;
        // configure cell
        MRWebListTableViewCell  *api1Cell = [tableView dequeueReusableCellWithIdentifier:@"YourAPI1Cell"];

        ...

        // Top Image View
        // for example: fDan.imageURL is a image URL string
        [api1Cell.topImageView sd_setImageWithURL:[NSURLURLWithString: fDan.imageURL]
                                 placeholderImage:[UIImage imageNamed: @"e_r.png"]];
rintaro
  • 51,423
  • 14
  • 131
  • 139
2

Seems like iOS 8's auto cell height isn't working too well. I faced similar issues in iOS 6 / 7 and after I updated to iOS 8 it still works. So maybe you should go old school for the time being.

I have some examples of my code here: AutoLayout multiline UILabel cutting off some text

And here: AutoLayout uitableviewcell in landscape and on iPad calculating height based on portrait iPhone

Long story short the pre iOS 8 way involved keeping a copy of a cell just for calculating the height inside tableView:heightForRowAtIndexPath:. But this wasn't enough for dealing with multi line UILabel's. I had to subclass UILabel to update the preferredMaxLayoutWidth every time layoutSubviews was called.

The preferredMaxLayoutWidth "fix" seemed to be the magic secret I was missing. Once I did this most of my cells worked perfectly.

The second issue I had only required me to set the content compression resistance and content hugging properties correctly, so for example telling the label to hug the text will mean it won't expand to fill the whitespace which will cause the cell to shrink.

Once I did these 2 things my cells now handle any font size, or any amount of text without any messy layout code. It was a lot to learn but I do think it paid off in the end, as I have a lot of dynamic content in my app.

Edit

After coming across a few issues of my own with iOS 8, i'm adding some more details to solve these very odd autoLayout bugs.

With the code I mentioned, it doesn't seem to work when the cell "Row Height" is not set to custom. This setting is found in IB by selecting the cell and clicking the autoLayout tab (where all the content compression resistance settings etc are). Press the checkbox and it will fill with a temporary height.

Second is, in my code I keep a local copy of a cell, and then reuse it many times inside the heightForRowAtIndexPath: method. This seems to increase the cell height by a lot every time it is called. I had to re-init the local copy by calling:

localCopy = [self.tableView dequeueReusableCellWithIdentifier:@"mycell"];

It appears the new Xcode 6 / iOS 8 changes are very much so not backwards compatible with iOS 7 and it seems to be managed quite differently.

Hope this helps.

Edit 2

after reading this question: iOS AutoLayout multi-line UILabel

I've come across another issue with iOS 7 / iOS 8 autolayout support!!! I was overriding layoutSubviews for iOS 8 I also needed to override setBounds to update the preferredMaxLayoutWidth after calling super. WTF have apple changed!

Seems to be an issue with the setting in IB for preferredMaxLayoutWidth, because iOS 7 can't use the automatic feature, if you use the same UILabel on multiple devices, its only going to use the 1 width. So UITableViewCell's on an iOS 8 tablet will be bigger because the same cell needs to have 2 lines on an iOS 8 iPhone.

Community
  • 1
  • 1
Simon McLoughlin
  • 8,293
  • 5
  • 32
  • 56
  • Thanks I'm going to try this out! – Realinstomp Oct 08 '14 at 15:53
  • I'm only looking for iOS8 support, does that pare back some of your answer at all? Thanks again Simon! – Realinstomp Oct 17 '14 at 23:51
  • @Reez I'm not sure if targeting only 8 improves things. I haven't tested it as I can't do that for my current app. All I no is I've logged a bug against apple for the first time and I'm finding issues by the bucket load since. I gave up yesterday and set my base SDK to 7 and it seemed to fix all my autoLayout issues. I found another issue in 8 where for one cell with 7 labels, it will appear with 2 of them squashed and after 6 seconds it randomly calls setBounds again on 3 and updates the cell. I have no code running and i don touch the cell. It just happens for no reason – Simon McLoughlin Oct 18 '14 at 09:08
  • @Reez I've started a thread on the developer forum and at least one has commented back saying they are finding 8 so unstable. Next week I'm going to experiment with seeing can I target 7 in Xcode 6 and optimise the app for iPhone 6 / 6+. If I can I'm dropping 8 support until apple fix this stuff – Simon McLoughlin Oct 18 '14 at 09:10
  • Awesome Simon, thanks for the good info on that. Thats kinda crazy if 8 is that unstable. – Realinstomp Oct 18 '14 at 13:13
  • @Reez just downloaded 8.1, seems to have fixed all my issues. I'd highly recommend updating! – Simon McLoughlin Oct 21 '14 at 10:08
1

I believe if you are adding subviews to a UITableViewCell and using AutoLayout you will get undesired results due to auto resizing. Try calling setTranslatesAutoresizingMaskINtoConstraints: NO on the subviews of the UITableViewCell.

egarlock
  • 559
  • 3
  • 11