Context: I have a collection view with dynamic cell height defined by its cell's content. The cell's content: a UIView, a UILabel, and a UIImage (image and label vertically positioned).
Problem: Autolayout seems to work and size the cell accordingly when I have the image contentMode as scaleAspectFill. However, this crops image's sides. When I set the contentMode to scaleAspectFit it sizes the images correctly horizontally, but maintains the former height.
Attaching images of the results. Thanks for any tips and support!
Code for collection view layout:
func createLayout() -> UICollectionViewLayout {
let _: CGFloat = (self.view.frame.width*1.33) + 50
let estimatedHeight = CGFloat(100)
let layoutSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(estimatedHeight))
let item = NSCollectionLayoutItem(layoutSize: layoutSize)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: layoutSize,
repeatingSubitem: item,
count: 1)
let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
section.interGroupSpacing = 10
let layout = UICollectionViewCompositionalLayout(section: section)
return layout
}
For Cell Registration:
let newCell = UICollectionView.CellRegistration<CustomCell, Asset> {(cell, indexPath, item) in
let image = UIImage(named: "test")
cell.label.text = "No comments"
cell.imageView.image = image
}
For the custom cell:
class CustomGroupItemCell: UICollectionViewCell {
let container = UIView()
let imageView = UIImageView()
let label = UILabel()
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("not implemnted")
}
func configure() {
container.translatesAutoresizingMaskIntoConstraints = false
imageView.translatesAutoresizingMaskIntoConstraints = false
label.translatesAutoresizingMaskIntoConstraints = false
label.adjustsFontForContentSizeCategory = true
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 17, weight: .semibold)
label.textColor = .label
container.backgroundColor = .secondarySystemFill
container.layer.cornerRadius = 12
imageView.layer.cornerRadius = 5
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
contentView.addSubview(container)
contentView.addSubview(label)
contentView.addSubview(imageView)
let views = [ "label": label, "container": container, "image": imageView]
var constraints = [NSLayoutConstraint]()
// Horizontal
constraints.append(contentsOf: NSLayoutConstraint.constraints(
withVisualFormat: "H:|[container]|", options: [], metrics: nil, views: views))
constraints.append(contentsOf: NSLayoutConstraint.constraints(
withVisualFormat: "H:|-20-[image]-20-|", options: [], metrics: nil, views: views))
constraints.append(contentsOf: NSLayoutConstraint.constraints(
withVisualFormat: "H:|-20-[label]-20-|", options: [], metrics: nil, views: views))
// Vertical
constraints.append(contentsOf: NSLayoutConstraint.constraints(
withVisualFormat: "V:|[container]|",
options: [], metrics: nil, views: views))
constraints.append(contentsOf: NSLayoutConstraint.constraints(
withVisualFormat: "V:|-20-[image]-20-[label]-24-|",
options: [], metrics: nil, views: views))
NSLayoutConstraint.activate(constraints)
}
}


You cannot do this in any automagic way. When an image is ready to be placed in a cell, you need to read its size and adjust the image view's size constraints accordingly.
For example, in my app, the image view and cell width are fixed. When the image arrives, I work out its aspect ratio and set that value as the multiplier of the image view's aspect ratio constraint, thus setting the height to fit the image.