166 lines
6.3 KiB
Swift
166 lines
6.3 KiB
Swift
//
|
|
// Table.swift
|
|
// VDS
|
|
//
|
|
// Created by Nadigadda, Sumanth on 24/04/24.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import VDSCoreTokens
|
|
|
|
///Table is view composed of rows and columns, which takes any view into each cell and resizes based on the highest cell height.
|
|
@objcMembers
|
|
@objc(VDSTable)
|
|
open class Table: View {
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Private Properties
|
|
//--------------------------------------------------
|
|
|
|
/// CollectionView to show the rows and columns
|
|
private lazy var matrixView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: flowLayout).with {
|
|
$0.register(TableCellItem.self, forCellWithReuseIdentifier: TableCellItem.Identifier)
|
|
$0.dataSource = self
|
|
$0.delegate = self
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
$0.allowsSelection = false
|
|
$0.showsVerticalScrollIndicator = false
|
|
$0.showsHorizontalScrollIndicator = false
|
|
$0.isAccessibilityElement = true
|
|
$0.backgroundColor = .clear
|
|
}
|
|
|
|
/// 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
|
|
private var tableData: [TableRowModel] {
|
|
return tableHeader + tableRows
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Enums
|
|
//--------------------------------------------------
|
|
|
|
/// Enums used to define the padding for the cell edge spacing.
|
|
public enum Padding: String, CaseIterable {
|
|
case standard, compact
|
|
|
|
func horizontalValue() -> CGFloat {
|
|
switch self {
|
|
case .standard, .compact:
|
|
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space3X
|
|
}
|
|
}
|
|
|
|
func verticalValue() -> CGFloat {
|
|
switch self {
|
|
case .standard:
|
|
return UIDevice.isIPad ? VDSLayout.space8X : VDSLayout.space6X
|
|
case .compact:
|
|
return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space3X
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Public Properties
|
|
//--------------------------------------------------
|
|
|
|
/// Parameter to set striped status for the table
|
|
open var striped: Bool = false { didSet { setNeedsUpdate() } }
|
|
|
|
/// Parameter to set the padding for the cell
|
|
open var padding: Padding = .standard { didSet { setNeedsUpdate() } }
|
|
|
|
/// Parameter to show the table header row
|
|
open var tableHeader: [TableRowModel] = [] { didSet { setNeedsUpdate() } }
|
|
|
|
/// Parameter to show the all table rows
|
|
open var tableRows: [TableRowModel] = [] { didSet { setNeedsUpdate() } }
|
|
|
|
open var fillContainer: Bool = true { didSet { setNeedsUpdate() } }
|
|
|
|
open var columnWidths: [CGFloat]? { didSet { setNeedsUpdate() } }
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Overrides
|
|
//--------------------------------------------------
|
|
|
|
///Called upon initializing the table view
|
|
open override func setup() {
|
|
super.setup()
|
|
addSubview(matrixView)
|
|
matrixView.pinToSuperView()
|
|
}
|
|
|
|
/// 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()
|
|
}
|
|
|
|
open override func setDefaults() {
|
|
super.setDefaults()
|
|
striped = false
|
|
padding = .standard
|
|
tableHeader = []
|
|
tableRows = []
|
|
fillContainer = true
|
|
columnWidths = nil
|
|
}
|
|
|
|
func calculateColumnWidths() -> [CGFloat] {
|
|
guard let noOfColumns = tableData.first?.columnsCount else { return [] }
|
|
let itemWidth = floor(matrixView.safeAreaLayoutGuide.layoutFrame.width / CGFloat(noOfColumns))
|
|
return Array(repeating: itemWidth, count: noOfColumns)
|
|
}
|
|
|
|
}
|
|
|
|
extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableCollectionViewLayoutDataDelegate {
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - UICollectionViewDelegate & UICollectionViewDataSource
|
|
//--------------------------------------------------
|
|
|
|
public func numberOfSections(in collectionView: UICollectionView) -> Int {
|
|
return tableData.count
|
|
}
|
|
public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
|
return tableData[section].columnsCount
|
|
}
|
|
|
|
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
|
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TableCellItem.Identifier, for: indexPath) as? TableCellItem else { return UICollectionViewCell() }
|
|
let currentItem = tableData[indexPath.section].columns[indexPath.row]
|
|
let shouldStrip = striped ? (indexPath.section % 2 != 0) : false
|
|
let isHeader = tableData[indexPath.section].isHeader
|
|
var edgePadding = UIEdgeInsets(top: padding.verticalValue(), left: 0, bottom: padding.verticalValue(), right: padding.horizontalValue())
|
|
edgePadding.left = (indexPath.row == 0 && !striped) ? VDSLayout.space1X : padding.horizontalValue()
|
|
cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: edgePadding, isHeader: isHeader)
|
|
return cell
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - TableCollectionViewLayoutDataDelegate
|
|
//--------------------------------------------------
|
|
|
|
func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel {
|
|
return tableData[indexPath.section].columns[indexPath.row]
|
|
}
|
|
|
|
func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat {
|
|
return columnWidths?[indexPath.row] ?? 0.0
|
|
}
|
|
}
|