I am trying to make a little horizontal UICollectionView in the top section of my app but every time I load the app there are always like 2 or 3 cells that don't load its content. And the cells that don't load are changing.
Here is what I have done:
public var collectionViewDates = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionViewDates)
collectionViewDates.frame = CGRect(x: 0,
y: 90,
width: view.width,
height: 50)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DatesCollectionViewCell.identifier, for: indexPath) as! DatesCollectionViewCell
cell.dateLabel.text = "I dag\(indexPath.row)"
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DatesCollectionViewCell.identifier, for: indexPath) as! DatesCollectionViewCell
return CGSizeMake(cell.dateLabel.width + 30, collectionView.height)
}
And in the cell:
public var dateLabel: UILabel = {
let label = UILabel()
label.text = "I dag"
label.adjustsFontSizeToFitWidth = true
label.font = .systemFont(ofSize: 20, weight: .bold)
label.backgroundColor = .systemBlue
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(dateLabel)
dateLabel.frame = CGRect(x: 0,
y: 0,
width: 50,
height: contentView.height)
dateLabel.center.y = contentView.center.y
dateLabel.center.x = contentView.center.x
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
I don't understand why the cells sometimes load because I have done this before with other horizontal UICollectionViews. But this time I was not so lucky.
First, spend a little time learning about auto-layout.
Second, if you want 50x50
cells, set the .itemSize
on the collection view's flow layout.
Take a look at this:
class ViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
public var collectionViewDates: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
let fl = UICollectionViewFlowLayout()
fl.scrollDirection = .horizontal
fl.minimumLineSpacing = 24.0
fl.minimumInteritemSpacing = 24.0
fl.itemSize = .init(width: 50.0, height: 50.0)
collectionViewDates = UICollectionView(frame: .zero, collectionViewLayout: fl)
collectionViewDates.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionViewDates)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
collectionViewDates.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
collectionViewDates.leadingAnchor.constraint(equalTo: g.leadingAnchor),
collectionViewDates.trailingAnchor.constraint(equalTo: g.trailingAnchor),
collectionViewDates.heightAnchor.constraint(equalToConstant: 64.0),
])
collectionViewDates.register(DatesCollectionViewCell.self, forCellWithReuseIdentifier: DatesCollectionViewCell.identifier)
collectionViewDates.dataSource = self
collectionViewDates.delegate = self
collectionViewDates.backgroundColor = .black
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DatesCollectionViewCell.identifier, for: indexPath) as! DatesCollectionViewCell
cell.dateLabel.text = "I dag\(indexPath.row)"
return cell
}
}
class DatesCollectionViewCell: UICollectionViewCell {
static let identifier: String = "datesCell"
public var dateLabel: UILabel = {
let label = UILabel()
label.text = "I dag"
label.adjustsFontSizeToFitWidth = true
label.font = .systemFont(ofSize: 20, weight: .bold)
label.backgroundColor = .systemBlue
label.textColor = .white
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
private func commonInit() {
dateLabel.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(dateLabel)
NSLayoutConstraint.activate([
dateLabel.topAnchor.constraint(equalTo: contentView.topAnchor),
dateLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
dateLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
dateLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
])
}
}
Result:
Edit
If you want the cells to size to fit the widths of the labels...
Give the flow layout an estimated item size:
//fl.itemSize = .init(width: 50.0, height: 50.0)
fl.estimatedItemSize = .init(width: 50.0, height: 50.0)
and don't set the label to autoshrink the font:
//label.adjustsFontSizeToFitWidth = true