I want to display a NSCollectionLayoutItem( contains a image from remote and its aspect ratio is unkown) occupy the device screen horizontally , and still get the correct aspect ratio in Vertical .
So I use the NSCollectionLayoutDimension.estimated(50) points for height . but after the image is downloaded , the height is still 50 ,which is not enough for display the image .
How to make the layout automatically fit the image's content.
the image link is here : [image src] (https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png)
and the running result will be like this
the UICollectionView configuration code :
import UIKit
class ViewController: UIViewController {
enum Section {
case main
}
@IBOutlet weak var collectionView: UICollectionView!
var dataSource: UICollectionViewDiffableDataSource<Section, Int>! = nil
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
self.configDataSource()
self.configLayout()
}
func configDataSource() {
let imageCellReg = UICollectionView.CellRegistration<ImageCell,Int>(cellNib: UINib(nibName: "ImageCell", bundle: nil)) { cell, indexPath, itemIdentifier in
}
self.dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: self.collectionView, cellProvider: { collectionView, indexPath, itemIdentifier in
return self.collectionView.dequeueConfiguredReusableCell(using: imageCellReg, for: indexPath, item: itemIdentifier)
})
var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
snapshot.appendSections([.main])
snapshot.appendItems(Array(0..<2))
dataSource.apply(snapshot, animatingDifferences: false)
}
func configLayout(){
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .fractionalHeight(1.0))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension:.estimated(50))
let group = NSCollectionLayoutGroup.horizontal(layoutSize:groupSize, subitems: [item])
let spacing = CGFloat(10)
group.interItemSpacing = .fixed(spacing)
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = spacing
section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 10, bottom: 0, trailing: 10)
let layout = UICollectionViewCompositionalLayout(section: section)
self.collectionView.collectionViewLayout = layout
}
}
And the cell code:
import UIKit
import SDWebImage
class ImageCell: UICollectionViewCell {
@IBOutlet weak var imageContentView: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
imageContentView.sd_setImage(with: URL(string: "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png"))
}
}
Very quick example...
Design your cell like this:
We've given the image view a Height constraint -- which will be updated when the image has been downloaded.
The cell class is as simple as this:
class ImageCell: UICollectionViewCell {
@IBOutlet var imageContentView: UIImageView!
@IBOutlet var imgHeight: NSLayoutConstraint!
}
Using SDWebImage
, we'll implement a completion block, where we'll calculate the aspect-ratio height for the downloaded image, which we'll use to set the imgHeight.constant
. We then call collectionView.collectionViewLayout.invalidateLayout()
to tell the controller to re-layout the cells:
cell.imageContentView.sd_setImage (
with: URL(string: urlStr),
placeholderImage: UIImage(named: "somePlaceholder"),
options: SDWebImageOptions(rawValue: 0),
completed: { [weak self] image, error, cacheType, imageURL in
guard let self = self,
let img = image
else { return }
// calculate proportional height
let iw = cell.imageContentView.frame.width
let ih = (img.size.height / img.size.width) * iw
// update the height contraint in the cell
cell.imgHeight.constant = ih
// tell the collection view to re-layout the cells
self.collectionView.collectionViewLayout.invalidateLayout()
}
)
Here is a complete example project: https://github.com/DonMag/SDWebCV