class BookingController: UIViewController, UITableViewDelegate, UITableViewDataSource { // NEVER do something like this!!! // create a UITableViewCell subclass //let calendarCell = UITableViewCell() override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .gray // Manager.Colors.dark if let img = UIImage(named: "Background Image") { addBackgroundImage(image: img) } setupTableContent() } private func addBackgroundImage(image: UIImage) { let backgroundImage = UIImageView(image: image) backgroundImage.frame = view.bounds backgroundImage.alpha = 0.5 view.addSubview(backgroundImage) } override var preferredStatusBarStyle: UIStatusBarStyle { .lightContent } private func setupTableContent() { let tableView = UITableView() tableView.backgroundColor = .clear tableView.delegate = self tableView.dataSource = self tableView.translatesAutoresizingMaskIntoConstraints = false tableView.estimatedRowHeight = 80 tableView.rowHeight = UITableView.automaticDimension view.addSubview(tableView) // register CalendarCell class tableView.register(CalendarCell.self, forCellReuseIdentifier: "calendarCell") [tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor), tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)].forEach({$0.isActive = true}) } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // dequeue a CalendarCell and set its Data let cell = tableView.dequeueReusableCell(withIdentifier: "calendarCell", for: indexPath) as! CalendarCell cell.initData() return cell } func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { UIView() } } // custom table view cell class CalendarCell: UITableViewCell { let calendarView = CalendarView() // we will set the .constant on this constraint to set the height of the // calendarView (and thus the height of the collection view) var calendarViewHeightConstraint: NSLayoutConstraint! override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) commonInit() } required init?(coder: NSCoder) { super.init(coder: coder) commonInit() } func commonInit() -> Void { calendarView.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(calendarView) calendarView.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true calendarView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true calendarView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true // bottom anchor needs to have Priority less than required to avoid auto-layout complaints let c = calendarView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) c.priority = .defaultHigh c.isActive = true // initial height constant doesn't matter... it will be changed when we set the data calendarViewHeightConstraint = calendarView.heightAnchor.constraint(equalToConstant: 10.0) calendarViewHeightConstraint.isActive = true } var m: Int = 0 // tiene traccia del mese var y: Int = 0 // tiene traccia dell'anno var totalCellsNeeded: Int = 0 // number of cell func initData() { let calendar = Calendar.current m = Calendar.current.component(.month, from: Date()) y = Calendar.current.component(.year, from: Date()) let dateComponents = DateComponents(year: y, month: m) guard let startDate = calendar.date(from: dateComponents) else { fatalError("Something is wrong with the date!") } guard let range = calendar.range(of: .day, in: .month, for: startDate) else { fatalError("Something is wrong with the date!") } let numberOfDaysInMonth = range.count let startDayOfWeek = Calendar.current.component(.weekday, from: startDate) totalCellsNeeded = numberOfDaysInMonth + (startDayOfWeek - 1) let numRows = Int(ceil(Double(totalCellsNeeded) / Double(7))) // we now know the Height needed for the collection view // you said your calendar cell height is 75, so... // cvHeight = numRows * 75 calendarViewHeightConstraint.constant = CGFloat(numRows * 75) // give these values to the calendarView to be used // for the collection view data calendarView.startDayOfWeek = startDayOfWeek calendarView.totalCellsNeeded = totalCellsNeeded } } // CALENDAR VIEW class CalendarView: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { // these are set by the cell class var startDayOfWeek: Int = 0 var totalCellsNeeded: Int = 0 // number of cell override init(frame: CGRect) { super.init(frame: frame) backgroundColor = .red let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()) collectionView.delegate = self collectionView.dataSource = self collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.backgroundColor = .clear addSubview(collectionView) collectionView.register(DaysCell.self, forCellWithReuseIdentifier: "cellDay") collectionView.topAnchor.constraint(equalTo: topAnchor).isActive = true collectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true collectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true collectionView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true // no height anchor //collectionView.heightAnchor.constraint(equalToConstant: 200).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { totalCellsNeeded } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellDay", for: indexPath) as! DaysCell // startDayOfWeek is 1-based cell.populateCell(indexPath.item - (startDayOfWeek - 1)) return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { .init(width: collectionView.frame.width / 7, height: 75) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { 0 } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { 0 } } // Day CELL class DaysCell: UICollectionViewCell { private let dayLbl = UILabel() override init(frame: CGRect) { super.init(frame: frame) dayLbl.translatesAutoresizingMaskIntoConstraints = false addSubview(dayLbl) dayLbl.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true dayLbl.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func populateCell(_ i: Int) -> Void { if i >= 0 { dayLbl.text = "\(i + 1)" } } }