106 lines
3.6 KiB
Swift
106 lines
3.6 KiB
Swift
//
|
|
// 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) -> TableItemModel
|
|
}
|
|
|
|
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..<sections {
|
|
|
|
let items = collectionView.numberOfItems(inSection: currentSection)
|
|
|
|
for currentItem in 0..<items {
|
|
|
|
let indexPath = IndexPath(row: currentItem, section: currentSection)
|
|
|
|
let itemWidth = floor(collectionView.safeAreaLayoutGuide.layoutFrame.width / CGFloat(items))
|
|
|
|
let selectedItem = delegate.collectionView(collectionView, dataForItemAt: indexPath)
|
|
|
|
let itemHeight = estimateHeightFor(item: selectedItem, with: itemWidth)
|
|
|
|
let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath)
|
|
|
|
let origin = CGPoint(x: itemWidth * CGFloat(indexPath.row), y: yPos)
|
|
|
|
let size = CGSize(width: itemWidth, height: itemHeight)
|
|
|
|
attribute.frame = CGRect(origin: origin, size: size)
|
|
|
|
itemCache.append(attribute)
|
|
}
|
|
|
|
let highestHeightForSection = itemCache.sorted(by: {$0.frame.size.height > $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: TableItemModel, with width: CGFloat) -> CGFloat {
|
|
|
|
let itemWidth = width - layoutPadding.horizontalValue() - VDSLayout.space1X
|
|
let height = item.component.estimatedHeight(for: itemWidth) ?? 0
|
|
return height + (2 * layoutPadding.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
|
|
}
|
|
}
|