-->

UICollectionViewFlowLayout estimatedItemSize does

2020-02-18 09:41发布

问题:

For UICollectionView's dynamic height cells we use,

if let layout = self.collectionViewLayout as? UICollectionViewFlowLayout {
    layout.estimatedItemSize = UICollectionViewFlowLayoutAutomaticSize
}

with the proper constraint of height and width, it works fine with iOS 11.* versions but it breaks and does not make the cells dynamic for iOS 12.0

回答1:

In my case, I solved this by explicitly adding the following constraints to the cell's contentView.

class Cell: UICollectionViewCell {
    // ...

    override func awakeFromNib() {
        super.awakeFromNib()

        // Addresses a separate issue and prevent auto layout warnings due to the temporary width constraint in the xib.
        contentView.translatesAutoresizingMaskIntoConstraints = false

        // Code below is needed to make the self-sizing cell work when building for iOS 12 from Xcode 10.0:
        let leftConstraint = contentView.leftAnchor.constraint(equalTo: leftAnchor)
        let rightConstraint = contentView.rightAnchor.constraint(equalTo: rightAnchor)
        let topConstraint = contentView.topAnchor.constraint(equalTo: topAnchor)
        let bottomConstraint = contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
        NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
    }
}

These constraints are already in place inside the xib of the cell, but somehow they aren't enough for iOS 12.

The other threads that suggested calling collectionView.collectionViewLayout.invalidateLayout() in various places didn't help in my situation.

Sample code here: https://github.com/larrylegend/CollectionViewAutoSizingTest

This applies the workaround to code from a tutorial by https://medium.com/@wasinwiwongsak/uicollectionview-with-autosizing-cell-using-autolayout-in-ios-9-10-84ab5cdf35a2:



回答2:

Based on ale84's answer and because of the fact I needed that iOS 12 fix in multiple places I created a UICollectionViewCell extension which I named UICollectionViewCell+iOS12:

extension UICollectionViewCell {
    /// This is a workaround method for self sizing collection view cells which stopped working for iOS 12
    func setupSelfSizingForiOS12(contentView: UIView) {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        let leftConstraint = contentView.leftAnchor.constraint(equalTo: leftAnchor)
        let rightConstraint = contentView.rightAnchor.constraint(equalTo: rightAnchor)
        let topConstraint = contentView.topAnchor.constraint(equalTo: topAnchor)
        let bottomConstraint = contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
        NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
    }
}

And then in your collection view cells we do something like this (if your cell is created in IB):

override func awakeFromNib() {
    super.awakeFromNib()
    if #available(iOS 12, *) { setupSelfSizingForiOS12(contentView: contentView) }
}


回答3:

Objective C version of above answer:

-(void)awakeFromNib{
    [super awakeFromNib];

    if (@available(iOS 12.0, *)) {
        // Addresses a separate issue and prevent auto layout warnings due to the temporary width constraint in the xib.
        self.contentView.translatesAutoresizingMaskIntoConstraints = NO;

        // Code below is needed to make the self-sizing cell work when building for iOS 12 from Xcode 10.0:

        NSLayoutConstraint *leftConstraint = [self.contentView.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:0];
        NSLayoutConstraint *rightConstraint = [self.contentView.rightAnchor constraintEqualToAnchor:self.rightAnchor constant:0];
        NSLayoutConstraint *topConstraint = [self.contentView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0];
        NSLayoutConstraint *bottomConstraint = [self.contentView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0];

        [NSLayoutConstraint activateConstraints:@[leftConstraint, rightConstraint, topConstraint, bottomConstraint]];
    }

}

For Objective-C lovers like me ;) cheers !!!



回答4:

i have the same problem. using UILabels to size the collectionview. if i run collectionView.collectionViewLayout.invalidateLayout() before reloading the data it does an ok job of sizing the labels.

still not quite right. it's tough for me to figure because i'm running it on the simulator vs. device.



回答5:

I managed to solve this problem by putting such code into my subclass of UICollectionViewCell

- (UICollectionViewLayoutAttributes *)preferredLayoutAttributesFittingAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes {
    [self updateConstraintsIfNeeded];
    CGSize size = [self systemLayoutSizeFittingSize:CGSizeMake(1000, 1000)];

    CGRect alteredRect = layoutAttributes.frame;
    alteredRect.size = size;
    layoutAttributes.frame = alteredRect;
    return layoutAttributes;
}

and subclassing UICollectionView like this

@interface CustomCollectionView ()
@property (nonatomic) BOOL shouldInvalidateLayout;
@end

@implementation CustomCollectionView

- (void)layoutSubviews {
    [super layoutSubviews];
    if (self.shouldInvalidateLayout) {
        [self.collectionViewLayout invalidateLayout];
        self.shouldInvalidateLayout = NO;
    }
}

- (void)reloadData {
    self.shouldInvalidateLayout = YES;
    [super reloadData];
}

@end