// // TableFlowLayout.swift // VDS // // Created by Nadigadda, Sumanth on 02/05/24. // import UIKit import VDSTokens protocol TableCollectionViewLayoutDataDelegate: AnyObject { func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel } class MatrixFlowLayout : UICollectionViewLayout { weak var delegate: TableCollectionViewLayoutDataDelegate? var layoutPadding: Table.Padding = .standard var itemCache: [UICollectionViewLayoutAttributes] = [] var layoutHeight: CGFloat = 0.0 override func prepare() { super.prepare() itemCache.removeAll() layoutHeight = 0.0 guard let collectionView, let delegate else { return } let sections = collectionView.numberOfSections var yPos: CGFloat = 0.0 for currentSection in 0.. $1.frame.size.height }).first?.frame.size.height ?? 0.0 itemCache.filter({$0.indexPath.section == currentSection}).forEach { attributes in attributes.frame.size.height = highestHeightForSection } yPos += highestHeightForSection } layoutHeight = yPos } private func estimateHeightFor(item: TableCellModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat { if let model = item as? Table.TableCellLabelModel { return estimatedHeightForLabel(item: model, with: width, padding: padding, isHeader: isHeader) } return (item.defaultHeight + (2 * padding.verticalValue())) } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = [] for attributes in itemCache { if attributes.frame.intersects(rect) { visibleLayoutAttributes.append(attributes) } } return visibleLayoutAttributes } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return itemCache.filter({ $0.indexPath == indexPath}).first } override var collectionViewContentSize: CGSize { return CGSize(width: contentWidth, height: layoutHeight) } private var contentWidth: CGFloat { guard let collectionView = collectionView else { return 0 } return collectionView.bounds.width } } extension MatrixFlowLayout { private func estimatedHeightForLabel(item: Table.TableCellLabelModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat { let cellLabel = Label() cellLabel.textStyle = isHeader ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall cellLabel.text = item.text let labelWidth = width - padding.horizontalValue() - VDSLayout.space1X let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) let labelSize = cellLabel.sizeThatFits(maxbounds) return labelSize.height + (2 * padding.verticalValue()) } }