diff --git a/VDS/Components/Calendar/CalendarFooterReusableView.swift b/VDS/Components/Calendar/CalendarFooterReusableView.swift index 1a402dc3..9547084f 100644 --- a/VDS/Components/Calendar/CalendarFooterReusableView.swift +++ b/VDS/Components/Calendar/CalendarFooterReusableView.swift @@ -20,17 +20,26 @@ class CalendarFooterReusableView: UICollectionReusableView { private var surface: Surface = .light private var items: [CalendarBase.CalendarIndicatorModel] = [] internal var containerSize: CGSize { CGSize(width: 304, height: 40) } - + internal var indicatorWidth = 8.0 + + var textLabel: Label = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .left + $0.textStyle = .bodySmall + $0.numberOfLines = 1 + } + internal var containerView = View().with { $0.clipsToBounds = true } - private let flowLayout = UICollectionViewFlowLayout().with { + private let flowLayout = LeftAlignedCollectionViewFlowLayout().with { $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize $0.minimumLineSpacing = VDSLayout.space1X $0.minimumInteritemSpacing = VDSLayout.space4X $0.scrollDirection = .vertical } + open lazy var legendCollectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout).with { $0.isScrollEnabled = false $0.translatesAutoresizingMaskIntoConstraints = false @@ -45,6 +54,8 @@ class CalendarFooterReusableView: UICollectionReusableView { forCellWithReuseIdentifier: LegendCollectionViewCell.identifier) } + private var topConstraint: NSLayoutConstraint? + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -66,18 +77,17 @@ class CalendarFooterReusableView: UICollectionReusableView { isAccessibilityElement = false addSubview(containerView) - containerView - .pinTopLessThanOrEqualTo(topAnchor, VDSLayout.space6X, .defaultLow) - .pinBottom() - .pinLeadingGreaterThanOrEqualTo(leadingAnchor, VDSLayout.space3X, .defaultHigh) - .pinTrailingLessThanOrEqualTo(trailingAnchor, VDSLayout.space3X, .defaultHigh) - .width(containerSize.width - (2*VDSLayout.space3X)) - .heightLessThanEqualTo(containerSize.height) + containerView.pinToSuperView() // legend Collection View containerView.addSubview(legendCollectionView) - legendCollectionView.pinTop().pinBottom().pinLeading().pinTrailing().pinCenterY().pinCenterX() - + legendCollectionView + .pinTopLessThanOrEqualTo(topAnchor, VDSLayout.space6X, .defaultLow) + .pinBottom() + .pinLeading(VDSLayout.space3X) + .pinTrailing(VDSLayout.space3X) + .width(containerSize.width - (2 * VDSLayout.space3X)) + .heightGreaterThanEqualTo(16) } /// Updating UI to show legend with titles. @@ -85,6 +95,15 @@ class CalendarFooterReusableView: UICollectionReusableView { self.items = indicators self.surface = surface legendCollectionView.reloadData() + + var height = legendCollectionView.collectionViewLayout.collectionViewContentSize.height + if height > 0 { + topConstraint?.isActive = false + height = height > containerSize.height ? containerSize.height : height + let top = containerSize.height - height + topConstraint = legendCollectionView.topAnchor.constraint(equalTo: topAnchor, constant: top) + topConstraint?.isActive = true + } } } @@ -107,6 +126,14 @@ extension CalendarFooterReusableView: UICollectionViewDelegate, UICollectionView drawSemiCircle: indexPath.row == 2) return cell } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + textLabel.text = items[indexPath.row].label + let intrinsicSize = textLabel.intrinsicContentSize + let cellwidth = intrinsicSize.width + indicatorWidth + VDSLayout.space2X + return .init(width: min(cellwidth, collectionView.frame.width), height: intrinsicSize.height) + } + } private class LegendCollectionViewCell: UICollectionViewCell { @@ -130,6 +157,7 @@ private class LegendCollectionViewCell: UICollectionViewCell { $0.translatesAutoresizingMaskIntoConstraints = false $0.backgroundColor = .clear } + private var legendIndicator: View = View().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.backgroundColor = .clear @@ -138,7 +166,8 @@ private class LegendCollectionViewCell: UICollectionViewCell { private lazy var stackView = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false - $0.distribution = .equalSpacing + $0.alignment = .fill + $0.distribution = .fill $0.spacing = VDSLayout.space2X $0.axis = .horizontal $0.backgroundColor = .clear @@ -146,6 +175,8 @@ private class LegendCollectionViewCell: UICollectionViewCell { private lazy var shapeLayer = CAShapeLayer() + internal var indicatorSize: CGSize { CGSize(width: 8, height: 8) } + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -167,8 +198,9 @@ private class LegendCollectionViewCell: UICollectionViewCell { func updateView() { stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } legendIndicator.layer.sublayers?.forEach { $0.removeFromSuperlayer() } + legendIndicatorWrapper.addSubview(legendIndicator) - legendIndicator.pinLeading().pinTrailing().width(8).height(8).pinCenterY() + legendIndicator.pinLeading().pinTrailing().width(indicatorSize.width).height(indicatorSize.height).pinCenterY() stackView.addArrangedSubview(legendIndicatorWrapper) stackView.addArrangedSubview(title) @@ -201,3 +233,25 @@ private class LegendCollectionViewCell: UICollectionViewCell { legendIndicator.layer.addSublayer(shapeLayer) } } + +class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout { + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + let attributes = super.layoutAttributesForElements(in: rect) + + var leftMargin = sectionInset.left + var maxY: CGFloat = -1.0 + attributes?.forEach { layoutAttribute in + if layoutAttribute.frame.origin.y >= maxY { + leftMargin = sectionInset.left + } + + layoutAttribute.frame.origin.x = leftMargin + + leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing + maxY = max(layoutAttribute.frame.maxY , maxY) + } + + return attributes + } +}