I have never seen a topic with so many different answers than I have for setting a dynamic height for a collection view cell. Some of the solutions have unimaginable amounts of code, which only further lends to the consensus that UICollectionView
is a cluster since this can be achieved with a UITableView
without doing anything since dynamic cell height is built in when the constraints are chained properly. But I want to get a better handle on the collection view. And it's a nightmare.
How do I set the height of a collection view cell to be dynamic to its content size programmatically (no storyboards) in Swift without a hundred lines of code?
You can plug the following into a blank project and it will run clean if you feel so inclined.
CollectionViewFlowLayout:
class CollectionViewFlowLayout: UICollectionViewFlowLayout {
// inits
override init() {
super.init()
config()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// config
func config() {
scrollDirection = .vertical
minimumLineSpacing = 0
minimumInteritemSpacing = 0
}
}
CollectionViewController
class CollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
// model properties
let colorArray: [UIColor] = [.red, .green, .blue, .yellow]
let labelArray: [String] = [
"sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf",
"sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf",
"sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf",
"sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf sconewolf"
]
// view did load
override func viewDidLoad() {
super.viewDidLoad()
config()
}
// config
func config() {
collectionView?.dataSource = self
collectionView?.delegate = self
collectionView?.backgroundColor = UIColor.gray
collectionView?.contentInset = UIEdgeInsets(top: -20, left: 0, bottom: 0, right: 0)
collectionView?.alwaysBounceVertical = true
collectionView?.alwaysBounceHorizontal = false
collectionView?.register(CollectionViewCell.self, forCellWithReuseIdentifier: "cell1")
}
// data source: number of items in section
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return colorArray.count
}
// data source: cell for item
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! CollectionViewCell
cell.backgroundColor = colorArray[indexPath.item]
cell.label.text = labelArray[indexPath.item]
return cell
}
// delegate: size for item
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 200)
}
}
CollectionViewCell
class CollectionViewCell: UICollectionViewCell {
// view properties
var label = UILabel()
// inits
override init(frame: CGRect) {
super.init(frame: frame)
config()
addLabel()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// config
func config() {
self.translatesAutoresizingMaskIntoConstraints = false
}
// add label
func addLabel() {
label.font = UIFont.boldSystemFont(ofSize: 18)
label.textColor = UIColor.black
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
label.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
label.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
label.widthAnchor.constraint(equalTo: self.widthAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
label.sizeToFit()
}
}