Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionViewCell systemLayoutSizeFittingSize returns incorrect width

I've been toying with dynamic UICollectionViewCell's and have noticed that on iOS 8 calling cell.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize) on a UICollectionViewCell returns an incorrect width. Currently the only workaround that addresses this is to explicitly add a width constraint to force the cell's width. The below code is used in a Cell subclass:

func calculatePreferredHeightForFrame(frame: CGRect) -> CGFloat {
    var newFrame = frame
    self.frame = newFrame
    let widthConstraint = NSLayoutConstraint(item: contentView, attribute: .Width, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier: 1, constant: CGRectGetWidth(frame))
    contentView.addConstraint(widthConstraint)
    self.setNeedsUpdateConstraints()
    self.updateConstraintsIfNeeded()
    self.setNeedsLayout()
    self.layoutIfNeeded()
    let desiredHeight: CGFloat = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    newFrame.size.height = CGFloat(ceilf(Float(desiredHeight)))
    contentView.removeConstraint(widthConstraint)
    return CGRectGetHeight(newFrame)
}

I know that with iOS 8 and dynamic UICollectionViewFlowLayout that the UICollectionViewCell's contentView handles constraints differently but is there something I'm missing here? What does one need to do to ensure that systemLayoutSizeFittingSize uses a particular width on a cell?

I also came across this post (Specifying one Dimension of Cells in UICollectionView using Auto Layout) and believe this might actually invalidate my question. Perhaps UICollectionViewFlowLayout is not designed for cells with only one dynamic dimension, but that still doesn't explain why the cell gives an unusual width.

like image 823
Daniel Galasko Avatar asked Feb 23 '15 09:02

Daniel Galasko


2 Answers

I've faced same issue. The key is using priorities when getting systemLayoutSize.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    if (!self.prototypeCell) {
        self.prototypeCell = [TrainingMenuCell new];
        self.prototypeCell.contentView.translatesAutoresizingMaskIntoConstraints = NO;
    }

    [self configureCell:self.prototypeCell forIndexPath:indexPath];
    [self.prototypeCell setNeedsLayout];
    [self.prototypeCell layoutIfNeeded];

    CGFloat width = CGRectGetWidth(collectionView.frame) - 12;
    CGSize fittingSize = UILayoutFittingCompressedSize;
    fittingSize.width = width;

    CGSize size = [self.prototypeCell.contentView systemLayoutSizeFittingSize:fittingSize withHorizontalFittingPriority:UILayoutPriorityRequired verticalFittingPriority:UILayoutPriorityDefaultLow];
    return size;
}
like image 71
Timur Bernikovich Avatar answered Nov 15 '22 18:11

Timur Bernikovich


In my case, it was not calculating width correctly because I was missing those two lines before calling systemLayoutSizeFittingSize method:

[sizingCell setNeedsLayout];
[sizingCell layoutIfNeeded];

Spent hours to discover it so hope it could be helpful for others having similar issue.

like image 26
Pei Avatar answered Nov 15 '22 19:11

Pei