24

Since iOS 8 [UIColletionViewCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize] returns a size with height of 0.

Here's what the code does:

To determine the size for cell in a UICollectionView in iOS 7 I use systemLayoutSizeFittingSize: on a cell defined in a xib file using auto layout. The size depends on the font size of an UILabel being a subview of the UICollectionViewCell in my xib file. The label's font is set to UIFontTextStyleBody. So basically the cell's size depends on the font size setting made in iOS 7.

Here is the code itself:

+ (CGSize)cellSize {
    UINib *nib = [UINib nibWithNibName:NSStringFromClass([MyCollectionViewCell class]) bundle:nil];

    // Assumption: The XIB file only contains a single root UIView.
    UIView *rootView = [[nib instantiateWithOwner:nil options:nil] lastObject];

    if ([rootView isKindOfClass:[MyCollectionViewCell class]]) {
        MyCollectionViewCell *sampleCell = (MyCollectionViewCell*)rootView;
        sampleCell.label.text = @"foo"; // sample text without bar

        [sampleCell setNeedsLayout];
        [sampleCell layoutIfNeeded];

        return [sampleCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
    }

    return CGSizeZero;

}

It works perfectly fine in iOS 7 but not in iOS 8. Unfortunately I have no clue why.

How can I get the auto layout size of the UICollectionViewCells in iOS 8?

PS: Using

 return [sampleCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

instead of

 return [sampleCell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

as somebody might suggest, doesn't make any difference.

Philip McDermott
  • 1,068
  • 1
  • 10
  • 9
martn_st
  • 2,576
  • 1
  • 24
  • 30
  • I have the same issue: on iOS 7 [cell systemLayoutSizeFittingSize:UILayoutFittingCompressedSize].height returns the right size: on iOS 8 always 0. I find this is building with either iOS7 OR iOS 8 SDKs. Sorry I can't help yet, but happy that I'm not the only one! I've filed this radar: 17959753 – Philip McDermott Aug 12 '14 at 16:40
  • I have exactly the same problem. I have been playing around with it the whole day and couldn't find a solution. Changing it to collectionViewCell.contentView did not help. – davidk Aug 13 '14 at 06:26
  • I am having the same problem, experimenting has shown that it might have something to do with the constraints being added via interface builder which are against the cell view instead of the cell.contentView. Adding constraints with code against the contentView solves this issue partially –  Aug 13 '14 at 08:34
  • @AlexLittlejohn it's UICollectionViewCells IB hides the content view, whereas with UITableViewCells it doesn't, which makes it harder to know where the constraints are being created. Like maremmle said in the question, [sampleCell.contentView systemLayoutSizeFittingSize:...] works in table view cells. The weird thing here is that it's definitely broken/changed on iOS 8, since building with either SDK fails on an iOS 8 device. – Philip McDermott Aug 13 '14 at 08:57
  • @AlexLittlejohn what do you mean by solving partially? Does the height come back as non-zero? – Philip McDermott Aug 13 '14 at 08:58
  • @PhilipMcDermott I mean it would return the correct size but the cell contents wouldn't always show up –  Aug 14 '14 at 09:05
  • We can only pray that this is fixed by Apple with GM, as we can not try if it was fixed with Beta 6. Did anybody already found a sensible workaround? – Matej Balantič Aug 26 '14 at 09:33
  • Still not fixed on Xcode 6 Beta 7. – ynnckcmprnl Sep 03 '14 at 12:09
  • After doing some further testing, it does appear to work on iOS8 GM when built with Xcode 6 GM. – ynnckcmprnl Sep 11 '14 at 09:04
  • For me, Xcode 6 GM it works under iOS 8 but now iOS 7 returns 0! =( – Adlai Holler Sep 11 '14 at 19:19
  • @AdlaiHoller I am having the exact same problem! Please update here if you find a solution. If its affecting iOS 7, would that be a bug with XCode and not the iOS 8 GM? – Blake Sep 11 '14 at 19:26
  • I found a fix in another Thread for this: http://stackoverflow.com/questions/24750158/autoresizing-issue-of-uicollectionviewcell-contentview-frame-in-storyboard-proto – mariusLAN Sep 22 '14 at 07:21

8 Answers8

8

What you need to do is wrap all of your content in a container view, then call:

return [sampleCell.containerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

Your cell should look like this: cell -> containerView -> sub views

This works on both ios7 & ios8.

Supposedly on ios8, all you have to do is set the estimateSize & cell will automatically auto size on its own. Apparently that's not working as of beta 6.

Triet Luong
  • 101
  • 1
  • 1
7

Looks like this officially a bug: I filed a report that was closed as a duplicate of this one

Will report back when Beta 6 is out.

[Update: working properly in the GM seed of iOS 8, and the bug has been closed by Apple.]

Philip McDermott
  • 1,068
  • 1
  • 10
  • 9
  • Thanks for your effort. Should i file a bug as well or do you think it will be fixed in Beta6 anyway? – martn_st Aug 14 '14 at 09:52
  • I think it's firmly on the radar now: maybe file one if it's not fixed in 6? – Philip McDermott Aug 15 '14 at 10:24
  • @maremmle You should always file a bug, even if it's a duplicate. Duplicate bug reports will raise the visibility of a particular bug to Apple, making it more likely to be addressed sooner rather than later. – memmons Aug 30 '14 at 19:52
  • 1
    @MichaelG.Emmons Alright I also submitted a bug report to Apple. – martn_st Sep 02 '14 at 14:10
  • 1
    My bug report was also marked as a duplicate of 17962954. http://openradar.appspot.com/search?query=17962954 – ynnckcmprnl Sep 05 '14 at 07:26
  • @PhilipMcDermott can you please report if fixed on iOS 8 GM? – kernix Sep 09 '14 at 19:28
  • This was resolved for me in the GM build released on Sep 9, 2014. Also, I am calling -systemLayoutSizeFittingSize on the cell, not the cell's contentView. – Blake Sep 10 '14 at 22:47
  • Indeed, I was too quick to jump to conclusions. It is working in iOS8 GM, I'm also calling systemLayoutSizeFittingSize on the cell. – ynnckcmprnl Sep 11 '14 at 09:05
  • For me it only worked only after adding a container view to the cell. – kernix Sep 11 '14 at 11:27
  • Confirmed that this works for me also as of the iOS 8 GM. I actually had to rebuild my cells' constraints but this was probably due to trying so many crazy workarounds in the betas. – Philip McDermott Sep 22 '14 at 15:14
  • I'll note that this was fixed for me in the iOS Simulator with 8.0 GM. But an iPad Retina fresh out of the box (assuming 8.0 GM?) still returned height of 0. Upgrading to 8.0.2 on the iPad has fixed the issue, it now returns the correct height. – pkamb Oct 01 '14 at 00:27
4

We're using a work-around for now, copied below. Hopefully, these issues will be resolved before iOS 8 release and we can remove this. (The kludge assumes knowledge of Apple's implicit contentView behavior, and we have to hack IB outlet references to any constraints we transfer.)

We notice they're also removing all autoresizingMasks from storyboards/NIBs during upgrade, which makes sense given it's supposed to be auto-layout, but collection views still throwback to springs & struts. Perhaps this has been overlooked in the purge?

--Dan

/**
 Kludge around cell sizing issues for iOS 8 and deployment to iOS 7 when compiled for 8.  Call this on the collection view cell before it is used, such as in awakeFromNib.  Because this manipulates top-level constraints, any references to such initial constraints, such as from IB outlets, will be invalidated.

 Issue 1: As of iOS 8 Beta 5, systemLayoutSizeFittingSize returns height 0 for a UICollectionViewCell.  In IB, cells have an implicit contentView, below which views placed in IB as subviews of the cell are actually placed.  However, constraints set between these subviews and its superview are placed on the cell, rather than the contentView (which is their actual superview).  This should be OK, as a constraint among items may be placed on any common ancestor of those items, but this is not playing nice with systemLayoutSizeFittingSize.  Transferring those constraints to be on the contentView seems to fix the issue.

 Issue 2: In iOS 7, prior to compiling against iOS 8, the resizing mask of the content view was being set by iOS to width+height.  When running on iOS 7 compiled against iOS 8 Beta 5, the resizing mask is None, resulting in constraints effecting springs for the right/bottom margins.  Though this starts out the contentView the same size as the cell, changing the cell size, as we do in the revealing list, is not tracked by changing it's content view.  Restore the previous behavior.

 Moving to dynamic cell sizing in iOS 8 may circumvent this issue, but that remedy isn't available in iOS 7.
*/
+ (void)kludgeAroundIOS8CollectionViewCellSizingIssues:(UICollectionViewCell *)cell {

    // transfer constraints involving descendants on cell to contentView
    UIView *contentView = cell.contentView;
    NSArray *cellConstraints = [cell constraints];
    for (NSLayoutConstraint *cellConstraint in cellConstraints) {
        if (cellConstraint.firstItem == cell && cellConstraint.secondItem) {
            NSLayoutConstraint *parallelConstraint = [NSLayoutConstraint constraintWithItem:contentView attribute:cellConstraint.firstAttribute relatedBy:cellConstraint.relation toItem:cellConstraint.secondItem attribute:cellConstraint.secondAttribute multiplier:cellConstraint.multiplier constant:cellConstraint.constant];
            parallelConstraint.priority = cellConstraint.priority;
            [cell removeConstraint:cellConstraint];
            [contentView addConstraint:parallelConstraint];
        } else if (cellConstraint.secondItem == cell && cellConstraint.firstItem) {
            NSLayoutConstraint *parallelConstraint = [NSLayoutConstraint constraintWithItem:cellConstraint.firstItem attribute:cellConstraint.firstAttribute relatedBy:cellConstraint.relation toItem:contentView attribute:cellConstraint.secondAttribute multiplier:cellConstraint.multiplier constant:cellConstraint.constant];
            parallelConstraint.priority = cellConstraint.priority;
            [cell removeConstraint:cellConstraint];
            [contentView addConstraint:parallelConstraint];
        }
    }

    // restore auto-resizing mask to iOS 7 behavior
    contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [cell setNeedsUpdateConstraints];
    [cell updateConstraintsIfNeeded];
}
PlayfulGeek
  • 923
  • 1
  • 7
  • 9
0

This is a bug in xCode6 and iOS 8 SDK running on iOS7 devices :) It almost waisted my day. Finally it worked with the below code in the UICollectionViewCell sub class. I hope this will be fixed with the next version

- (void)setBounds:(CGRect)bounds {
    [super setBounds:bounds];
    self.contentView.frame = bounds;
}
Krishna Kishore
  • 924
  • 8
  • 4
  • I do not recommend this fix. If you use systemLayoutSizeFittingSize: it will not work correctly since the contentView won't be part of the constraint hierarchy. You need to constraints on the contentView or set its autoResizingMask. – phatmann Oct 03 '14 at 17:45
0

I had the same issue for UITableViewCells and iOS 7 (ios8 works perfectly), but "Triet Luong" solution worked for me:

return [sampleCell.containerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];
Davis
  • 1,253
  • 4
  • 17
  • 38
0

This is not a bug, I have been grappling with this issue now for some time and have tried different things, I am giving below the steps that's worked for me:

1) use contentView [sampleCell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize];

2) you can create your own contentView and have the subViews added to the contentView, don't forget to pin the top, bottom and left and right of the contentView if you are using a custom contentView to the superView, if you don't do this then height will be 0, here also depending upon your requirements you can for. e.g not pin the bottom of the contentView to the superView so that the height of the view can vary, but pinning is important and pinning which one depends on your requirements.

3) set the constraints properly in interface builder depending upon your requirements, there are certain constraints that cannot be added in interface builder, but then you can add them in viewDidLoad of the viewController.

So my 2 cents input is that constraints have to be set properly in the interface builder for systemLayoutSizeFittingSize:UILayoutFittingCompressedSize to return correct dimensions, this is the solution guys.

0

maybe you have some wrong constrain, you should specify both virtical top space and bottom space between your UIView and contentView, i also had this issue before, that is because i just specified the virtical top space, and didn't specfied the virtical bottom space to contentView

Gene
  • 1
  • 1
-1

It was a bug in iOS 8 beta versions. Finally it is fixed with for iOS 8 GB (Build 12A365). So for me now it works with the same code I wrote for iOS 7. (see the question)

martn_st
  • 2,576
  • 1
  • 24
  • 30