// // RadioSwatchGroup.swift // VDS // // Created by Matt Bruce on 8/25/22. // import Foundation import UIKit import Combine @objc(VDSRadioSwatchGroup) open class RadioSwatchGroup: SelectorGroupSelectedHandlerBase, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- public override var selectorViews: [RadioSwatch] { didSet { collectionView.reloadData() } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- public var label = Label() private let cellSize: CGFloat = 48.0 private let labelSpacing: CGFloat = 24.0 private let labelHeight: CGFloat = 16.0 private let lineSpacing: CGFloat = 12.0 private let itemSpacing: CGFloat = 16.0 fileprivate lazy var collectionView: SelfSizingCollectionView = { let layout = UICollectionViewFlowLayout().with { $0.minimumLineSpacing = lineSpacing $0.minimumInteritemSpacing = itemSpacing } return SelfSizingCollectionView(frame: .zero, collectionViewLayout: layout).with { $0.backgroundColor = .clear $0.showsHorizontalScrollIndicator = false $0.showsVerticalScrollIndicator = false $0.isScrollEnabled = false $0.translatesAutoresizingMaskIntoConstraints = false $0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionViewCell") } }() //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- override public var disabled: Bool { didSet { for selector in selectorViews { selector.disabled = disabled } collectionView.reloadData() } } override public var surface: Surface { didSet { for selector in selectorViews { selector.surface = surface } collectionView.reloadData() } } open override func setup() { super.setup() addSubview(label) addSubview(collectionView) label .pinTop() .pinLeading() .pinTrailing() .height(labelHeight) collectionView .pinTop(label.bottomAnchor, labelSpacing) .pinLeading() .pinTrailing() .pinBottom() } open override func layoutSubviews() { super.layoutSubviews() // Accounts for any collection size changes DispatchQueue.main.async { self.collectionView.collectionViewLayout.invalidateLayout() } } public override func initialSetup() { super.initialSetup() collectionView.delegate = self collectionView.dataSource = self } open override func updateView() { label.textPosition = .left label.textStyle = .bodySmall label.text = selectedHandler?.text ?? " " label.surface = surface label.disabled = disabled collectionView.reloadData() } public func reload() { collectionView.reloadData() } //-------------------------------------------------- // MARK: - UICollectionViewDelegateFlowLayout //-------------------------------------------------- open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: cellSize, height: cellSize) } //-------------------------------------------------- // MARK: - UICollectionViewDelegate //-------------------------------------------------- open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { return !selectorViews[indexPath.row].disabled } open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { didSelect(selector: selectorViews[indexPath.row]) } //-------------------------------------------------- // MARK: - UICollectionViewDataSource //-------------------------------------------------- public func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return selectorViews.count } var cellsubs: [Int: AnyCancellable] = [:] public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath) let handler = selectorViews[indexPath.row] handler.onClick = { [weak self] handler in self?.didSelect(selector: handler) } cell.subviews.forEach { $0.removeFromSuperview() } cell.addSubview(handler) handler.pinToSuperView() return cell } public func didSelect(selector: RadioSwatch) { selectedHandler?.toggle() selector.toggle() label.text = selector.text didChange() valueChanged() } }