From 7748a5eae408b231f31d7ba0fc034cdcb2ea5209 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 24 May 2024 20:49:58 +0530 Subject: [PATCH] Changes to accommodate any ui element into table cell and make its size dynamic. --- VDS/Components/Table/Table.swift | 21 ++++++++++++++- VDS/Components/Table/TableCellModel.swift | 30 +++------------------- VDS/Components/Table/TableFlowLayout.swift | 28 +++++++++++--------- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 3c290a80..de03e8fc 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -24,7 +24,6 @@ open class Table: View { $0.delegate = self $0.translatesAutoresizingMaskIntoConstraints = false $0.allowsSelection = false - $0.isScrollEnabled = false $0.showsVerticalScrollIndicator = false $0.showsHorizontalScrollIndicator = false $0.isAccessibilityElement = true @@ -34,6 +33,7 @@ open class Table: View { /// Custom flow layout to manage the height of the cells private lazy var flowLayout = MatrixFlowLayout().with { $0.delegate = self + $0.scrollDirection = .horizontal } /// Array of ``TableItemModel`` by combining Header & Row items @@ -84,6 +84,9 @@ open class Table: View { /// Parameter to show the all table rows open var tableRows: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } + open var fillContainer: Bool = true { didSet { setNeedsUpdate() } } + + open var columnWidths: [CGFloat]? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Overrides @@ -99,6 +102,9 @@ open class Table: View { /// Will update the table view, when called becasue of any changes in component parameters open override func updateView() { super.updateView() + if fillContainer == true || (fillContainer == false && columnWidths == nil) { + columnWidths = calculateColumnWidths() + } flowLayout.layoutPadding = padding matrixView.reloadData() matrixView.collectionViewLayout.invalidateLayout() @@ -111,8 +117,17 @@ open class Table: View { padding = .standard tableHeader = [] tableRows = [] + fillContainer = true + columnWidths = nil setNeedsUpdate() } + + func calculateColumnWidths() -> [CGFloat] { + guard let noOfColumns = tableData.first?.count else { return [] } + let itemWidth = floor(matrixView.safeAreaLayoutGuide.layoutFrame.width / CGFloat(noOfColumns)) + return Array(repeating: itemWidth, count: noOfColumns) + } + } extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableCollectionViewLayoutDataDelegate { @@ -143,4 +158,8 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel { return tableData[indexPath.section][indexPath.row] } + + func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat { + return columnWidths?[indexPath.row] ?? 0.0 + } } diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift index 5253c67f..01f03515 100644 --- a/VDS/Components/Table/TableCellModel.swift +++ b/VDS/Components/Table/TableCellModel.swift @@ -9,40 +9,16 @@ import Foundation import UIKit import VDSTokens -/// Fetches the estimated height of component for said width -public protocol ComponentHeight { - func estimatedHeight(for width: CGFloat) -> CGFloat? -} - /// Model that represent the content of each cell of Table component public struct TableItemModel { - - /// Default cell height - public var defaultHeight: CGFloat { return 50.0 } - + public var bottomLine: Line.Style? /// Component to be show in the Table cell - public var component: UIView & ComponentHeight + public var component: UIView - public init(bottomLine: Line.Style? = nil, component: UIView & ComponentHeight) { + public init(bottomLine: Line.Style? = nil, component: UIView) { self.bottomLine = bottomLine self.component = component } } - -/// Confirming protocol ``ComponentHeight`` to determine the height, based on the width -extension Label: ComponentHeight { - - public func estimatedHeight(for width: CGFloat) -> CGFloat? { - let maxbounds = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) - return self.sizeThatFits(maxbounds).height - } -} - -extension Icon: ComponentHeight { - - public func estimatedHeight(for width: CGFloat) -> CGFloat? { - return intrinsicContentSize.height - } -} diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift index c66fa89e..0f3e231f 100644 --- a/VDS/Components/Table/TableFlowLayout.swift +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -10,9 +10,10 @@ import VDSTokens protocol TableCollectionViewLayoutDataDelegate: AnyObject { func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel + func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat } -class MatrixFlowLayout : UICollectionViewLayout { +class MatrixFlowLayout : UICollectionViewFlowLayout { //-------------------------------------------------- // MARK: - Private Properties @@ -27,6 +28,9 @@ class MatrixFlowLayout : UICollectionViewLayout { /// Parameter to store the total height of the collectionView private var layoutHeight: CGFloat = 0.0 + /// Parameter to store the total width of the collectionView + private var layoutWidth: CGFloat = 0.0 + //-------------------------------------------------- // MARK: - Internal Properties //-------------------------------------------------- @@ -57,6 +61,9 @@ class MatrixFlowLayout : UICollectionViewLayout { ///Looping through all the sections of the collectionView, visually these are rows for currentSection in 0.. $1.frame.size.height }).first?.frame.size.height ?? 0.0 + let highestHeightForSection = itemCache.filter({$0.indexPath.section == currentSection}).sorted(by: {$0.frame.size.height > $1.frame.size.height }).first?.frame.size.height ?? 0.0 ///Set the highest height as height to all the cells in the row to make the row in uniform height. itemCache.filter({$0.indexPath.section == currentSection}).forEach { attributes in @@ -102,8 +111,9 @@ class MatrixFlowLayout : UICollectionViewLayout { private func estimateHeightFor(item: TableItemModel, with width: CGFloat) -> CGFloat { let itemWidth = width - layoutPadding.horizontalValue() - defaultLeadingPadding - let height = item.component.estimatedHeight(for: itemWidth) ?? item.defaultHeight - return height + (2 * layoutPadding.verticalValue()) + let maxSize = CGSize(width: itemWidth, height: CGFloat.greatestFiniteMagnitude) + let estItemSize = item.component.systemLayoutSizeFitting(maxSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) + return estItemSize.height + (2 * layoutPadding.verticalValue()) } ///This will return the layout attributes for the elements in the defined rect @@ -124,12 +134,6 @@ class MatrixFlowLayout : UICollectionViewLayout { ///Returns the collectionview content size override var collectionViewContentSize: CGSize { - return CGSize(width: contentWidth, height: layoutHeight) - } - - /// Returns the width collectionView width - private var contentWidth: CGFloat { - guard let collectionView = collectionView else { return 0 } - return collectionView.bounds.width + return CGSize(width: layoutWidth, height: layoutHeight) } }