简体   繁体   English

UICollectionViewCell UIImageView 忽略 contentMode,溢出图像

[英]UICollectionViewCell UIImageView ignores contentMode, overflows image

A rather frustrating dilema where a UICollectionViewCell is rendered with a UIImageView as it's only subview.一个相当令人沮丧的困境,其中 UICollectionViewCell 使用 UIImageView 呈现,因为它只是子视图。 The frame is loaded when an async call to load the image completes the call and calls the setImage() method.当加载图像的异步调用完成调用并调用 setImage() 方法时加载框架。 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.然而,当在渲染单元格时将图像放入 UIImageView 时,图像不会应用 contentMode 属性,因此图像有效地浮动并以一种相当奇特的方式重叠相邻的单元格,滚动时会乱七八糟。

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).它是溢出每个单元格的图像(即使 clipToBounds 为真)。

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.如果我 .reloadData() 在集合上,那么单元格也会“修复”自己。 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.我不是 100% 它会解决这个问题,但是根据在 init 中传入的框架的宽度和高度在 init 中为图像视图创建一个框架可能会起作用。

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.只需使用界面构建器将集合视图的估计大小设置为无即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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