简体   繁体   中英

UICollectionViewCell UIImageView ignores contentMode, overflows image

A rather frustrating dilema where a UICollectionViewCell is rendered with a UIImageView as it's only subview. The frame is loaded when an async call to load the image completes the call and calls the setImage() method. So usually the cell is in view already before an image may have been set.

However, when the image is then placed into the UIImageView when the cell is rendered, the image doesn't apply the contentMode property, so the image effectively floats and overlaps neighbouring cells in a rather peculiar fashion that jumbles around when scrolling.

When the cell is re-used, ie, you scroll away from the broken area and then back into it, the cells appear normal again.

What you see when the cells load:

Scroll away then back into view, the cells organise themselves normally... The cells have an orange background color so they can be seen before the images have been loaded, all the cells do indeed render in the desired size/position. It's the image that overflows each cell (even though clipToBounds is true).

What causes this unusual behaviour? The image is loaded async from a server then cached locally. If I .reloadData() on the collection then the cells will also 'fix' themselves. Just after the first run or while loading do they appear all mixed up.

A code sample showing the cell re-use method and init method are as below:

class ThumbnailCell: UICollectionViewCell {
    var imageView: UIImageView!

    override init(frame: CGRect) {
        super.init(frame: frame)
        imageView = UIImageView(frame: contentView.bounds)
        imageView.image = nil
        imageView.clipsToBounds = true
        imageView.contentMode = .ScaleAspectFill
        imageView.setTranslatesAutoresizingMaskIntoConstraints(false)
        contentView.addSubview(imageView)
        let viewsDictionary = ["imageView" : imageView]
        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:[imageView]", options: .allZeros, metrics: nil, views: viewsDictionary))
        contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:[imageView]", options: .allZeros, metrics: nil, views: viewsDictionary))
    }

    func resetImage() {
        self.imageView.contentMode = .ScaleAspectFill
        self.imageView.frame = contentView.bounds
        self.imageView.clipsToBounds = true
    }

    func setImage(image: UIImage) {
        resetImage()
        self.imageView.image = image
    }

    override func prepareForReuse() {
        super.prepareForReuse()
        self.imageView.image = nil
        resetImage()
    }
}

I am not super useful when it comes to auto layout but I looks like the content view has constraints based on the image view which doesn't have a size or frame at that point. When you set the image you base the image view frame on the content view which is based on image view. This could explain why it is working correctly only after the first pass. I am not 100% it will fix the problem but creating a frame for the image view in the init based on the width and height of the frame being passed in on the init might work.

setTranslatesAutoresizingMaskIntoConstraints

Could be the main offender.

I was facing exactly same problem. The solution is from another question's answer .

Simply you just need to set estimated size of collection view to none using interface builder.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM