diff --git a/VDS/Classes/SelfSizingCollectionView.swift b/VDS/Classes/SelfSizingCollectionView.swift index 3a99404a..c50082c4 100644 --- a/VDS/Classes/SelfSizingCollectionView.swift +++ b/VDS/Classes/SelfSizingCollectionView.swift @@ -7,6 +7,7 @@ import Foundation import UIKit +import Combine /// UICollectionView subclassed to deal with Changing the size of itself based on its children and layout and changes of its contentSize. @objc(VDSSelfSizingCollectionView) @@ -34,10 +35,13 @@ public final class SelfSizingCollectionView: UICollectionView { // MARK: - Private Properties //-------------------------------------------------- private var contentSizeObservation: NSKeyValueObservation? + private var collectionViewHeight: NSLayoutConstraint? + private var anyCancellable: AnyCancellable? //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + /// The natural size for the receiving view, considering only properties of the view itself. public override var intrinsicContentSize: CGSize { let contentSize = self.contentSize @@ -63,12 +67,16 @@ public final class SelfSizingCollectionView: UICollectionView { //ensure autoLayout uses intrinsic height setContentHuggingPriority(.required, for: .vertical) setContentCompressionResistancePriority(.required, for: .vertical) + collectionViewHeight = heightAnchor.constraint(equalToConstant: 0).activate() // Observing the value of contentSize seems to be the only reliable way to get the contentSize after the collection view lays out its subviews. self.contentSizeObservation = self.observe(\.contentSize, options: [.old, .new]) { [weak self] _, change in // If we don't specify `options: [.old, .new]`, the change.oldValue and .newValue will always be `nil`. if change.newValue != change.oldValue { self?.invalidateIntrinsicContentSize() + if let height = change.newValue?.height { + self?.collectionViewHeight?.constant = height + } } } } diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index c361baee..6fdf4ff5 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -9,7 +9,6 @@ import Foundation import UIKit import VDSColorTokens import VDSFormControlsTokens -import Combine /// A button group contains combinations of related CTAs including ``Button``, ``TextLink``, and ``TextLinkCaret``. This group component controls a combination's orientation, spacing, size and allowable size pairings. @objc(VDSButtonGroup) @@ -63,9 +62,7 @@ open class ButtonGroup: View { open var buttons: [ButtonBase] = [] { didSet { setNeedsUpdate() } } private var _childWidth: ChildWidth? - - private var anyCancellable: AnyCancellable? - + /// If provided, width of Button components will be rendered based on this value. If omitted, default button widths are rendered. open var childWidth: ChildWidth? { get { _childWidth } @@ -105,7 +102,6 @@ open class ButtonGroup: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - fileprivate var collectionViewHeight: NSLayoutConstraint? fileprivate lazy var positionLayout = ButtonGroupPositionLayout().with { $0.position = .center @@ -134,12 +130,6 @@ open class ButtonGroup: View { super.setup() addSubview(collectionView) collectionView.pinToSuperView() - collectionViewHeight = heightAnchor.constraint(equalToConstant: VDS.Button.Size.large.height) - collectionViewHeight?.activate() - anyCancellable = positionLayout.$layoutHeight.receive(on: RunLoop.main).sink { [weak self] _ in - guard let self else { return } - self.collectionViewHeight?.constant = self.collectionView.intrinsicContentSize.height - } } //-------------------------------------------------- @@ -190,7 +180,6 @@ open class ButtonGroup: View { DispatchQueue.main.async { [weak self] in guard let self else { return } self.collectionView.collectionViewLayout.invalidateLayout() - self.collectionViewHeight?.constant = self.collectionView.intrinsicContentSize.height } } } diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift index c87f8989..ba0cec7c 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroupPositionLayout.swift @@ -193,6 +193,9 @@ class ButtonGroupPositionLayout: UICollectionViewLayout { // get the rect size of the button itemSize = delegate.collectionView(collectionView, sizeForItemAtIndexPath: indexPath) + // ensure the width is not greater than the collectionViewWidth + itemSize.width = min(itemSize.width, collectionViewWidth) + // determine if the current button will fit in the row let rowItemCount = rows.last?.attributes.count ?? 0