I have a horizontal UICollectionView
in which I display images that are loaded asynchronously. The cells are supposed to have their width fit the image.
In viewDidLoad
of my view controller, I set the estimated cell size:
(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.estimatedItemSize = CGSize(width: 400, height: 400)
In cellForItem
, I start the download task using Kingfisher:
cell.imageView.kf.setImage(with: url) { (_, _, _, _) in
cell.layoutSubviews()
}
Inside my cell, I have the following code inside the layoutSubviews
method:
// 326 is the image view's height
// .aspectRatio is a custom extension that returns: size.width / size.height
imageViewWidthConstraint.constant = 326 * image.aspectRatio
layoutIfNeeded()
In the storyboard, I have properly setup the layout constraints so that imageViewWidthConstraint
is respected for the cell's width.
The following is the result when running my app:
As you can see, the cells have a width of 400, although the image was loaded and the layout updated. And, as result, the images are stretched to fill the image view.
When I scroll to the right & then back, the cells are removed from the collection view and loaded back in, and are now properly laid out:
While scrolling, the cells adjust their width, sometimes to the correct width, sometimes to the wrong one.
What am I doing wrong here?
Since your images come in asynchronously it may take some time to be loaded. Only once they are loaded you can actually know the size or ratio of the image. That means for every image that is loaded you need to "reload" your layout. From a short search this looks promising.
At least this way you may get some animations, otherwise your cells will just keep jumping when images start to be loaded.
In any case I would advise you to avoid this. If I may assume; you are getting some data from server from which you use delivered URLs to download the images and show them on the collection view. The best approach (if possible) is to request that the API is extended so that you receive dimensions of images as well. So instead of
You could have
You can now use these values to generate aspect ratio width/height before you download the images.
Next to that I don't really see any good solution for the whole thing to look nice (without jumping around).