From 466dbb7c6a2d697020128a0b527931d62e079075 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 11 Mar 2024 12:47:16 -0500 Subject: [PATCH 1/5] update for TitleLockup for label compression/hugging Signed-off-by: Matt Bruce --- VDS/Components/TitleLockup/TitleLockup.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/VDS/Components/TitleLockup/TitleLockup.swift b/VDS/Components/TitleLockup/TitleLockup.swift index e11b674d..3802b529 100644 --- a/VDS/Components/TitleLockup/TitleLockup.swift +++ b/VDS/Components/TitleLockup/TitleLockup.swift @@ -68,6 +68,7 @@ open class TitleLockup: View { /// Label used to render the eyebrow model. open var eyebrowLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentHuggingPriority(.required, for: .vertical) } /// Model used in rendering the eyebrow label. @@ -77,6 +78,7 @@ open class TitleLockup: View { /// Label used to render the title model. open var titleLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentHuggingPriority(.required, for: .vertical) $0.accessibilityTraits.insert([.header]) } @@ -87,6 +89,7 @@ open class TitleLockup: View { /// Label used to render the subtitle model. open var subTitleLabel = Label().with { $0.setContentCompressionResistancePriority(.required, for: .vertical) + $0.setContentHuggingPriority(.required, for: .vertical) } /// Model used in rendering the subtitle label. @@ -380,7 +383,7 @@ open class TitleLockup: View { } //pin the last view to the bottom of this view - previousView?.pinBottom(0, .defaultHigh) + previousView?.pinBottom(0) //debugging for borders eyebrowLabel.debugBorder(show: hasDebugBorder, color: .green) From 4733a3a00c000300e6056d87fb0ec16d2cce3bba Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 11 Mar 2024 12:47:38 -0500 Subject: [PATCH 2/5] refactored to not use KVO, but a publisher KVO Signed-off-by: Matt Bruce --- VDS/Classes/SelfSizingCollectionView.swift | 24 ++++++++++++---------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/VDS/Classes/SelfSizingCollectionView.swift b/VDS/Classes/SelfSizingCollectionView.swift index c50082c4..6f37308c 100644 --- a/VDS/Classes/SelfSizingCollectionView.swift +++ b/VDS/Classes/SelfSizingCollectionView.swift @@ -34,7 +34,6 @@ public final class SelfSizingCollectionView: UICollectionView { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - private var contentSizeObservation: NSKeyValueObservation? private var collectionViewHeight: NSLayoutConstraint? private var anyCancellable: AnyCancellable? @@ -45,7 +44,6 @@ public final class SelfSizingCollectionView: UICollectionView { /// The natural size for the receiving view, considering only properties of the view itself. public override var intrinsicContentSize: CGSize { let contentSize = self.contentSize - //print(#function, contentSize) return CGSize(width: UIView.noIntrinsicMetric, height: contentSize.height) } @@ -68,17 +66,21 @@ public final class SelfSizingCollectionView: UICollectionView { 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 + + anyCancellable = self.publisher(for: \.contentSize, options: [.old, .new]) + .scan((old: CGSize.zero, new: CGSize.zero)) { accumulator, newValue in + // accumulator.old contains the old contentSize value + // accumulator.new contains the new contentSize value before the current update + // newValue is the current update to contentSize + return (old: accumulator.new, new: newValue) + } + .sink { [weak self] compare in + if compare.old != compare.new { + print("Old contentSize: \(compare.old), New contentSize: \(compare.new)") + self?.invalidateIntrinsicContentSize() + self?.collectionViewHeight?.constant = compare.new.height } } - } } } From 73c7e23b99bb099835323b8ea463a76b0acc71c7 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 11 Mar 2024 12:56:14 -0500 Subject: [PATCH 3/5] removed print Signed-off-by: Matt Bruce --- VDS/Classes/SelfSizingCollectionView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/VDS/Classes/SelfSizingCollectionView.swift b/VDS/Classes/SelfSizingCollectionView.swift index 6f37308c..d8656490 100644 --- a/VDS/Classes/SelfSizingCollectionView.swift +++ b/VDS/Classes/SelfSizingCollectionView.swift @@ -76,7 +76,6 @@ public final class SelfSizingCollectionView: UICollectionView { } .sink { [weak self] compare in if compare.old != compare.new { - print("Old contentSize: \(compare.old), New contentSize: \(compare.new)") self?.invalidateIntrinsicContentSize() self?.collectionViewHeight?.constant = compare.new.height } From 6aa09da464b7693edf207920193f378b2287a355 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 11 Mar 2024 13:51:19 -0500 Subject: [PATCH 4/5] refactored to have a public contentSize publisher Signed-off-by: Matt Bruce --- VDS/Classes/SelfSizingCollectionView.swift | 26 +++++++++++++--------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/VDS/Classes/SelfSizingCollectionView.swift b/VDS/Classes/SelfSizingCollectionView.swift index d8656490..6f4de7d0 100644 --- a/VDS/Classes/SelfSizingCollectionView.swift +++ b/VDS/Classes/SelfSizingCollectionView.swift @@ -36,7 +36,15 @@ public final class SelfSizingCollectionView: UICollectionView { //-------------------------------------------------- private var collectionViewHeight: NSLayoutConstraint? private var anyCancellable: AnyCancellable? - + private var contentSizeSubject = CurrentValueSubject(.zero) + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + public var contentSizePublisher: AnyPublisher { + contentSizeSubject.eraseToAnyPublisher() + } + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -67,17 +75,13 @@ public final class SelfSizingCollectionView: UICollectionView { setContentCompressionResistancePriority(.required, for: .vertical) collectionViewHeight = heightAnchor.constraint(equalToConstant: 0).activate() - anyCancellable = self.publisher(for: \.contentSize, options: [.old, .new]) - .scan((old: CGSize.zero, new: CGSize.zero)) { accumulator, newValue in - // accumulator.old contains the old contentSize value - // accumulator.new contains the new contentSize value before the current update - // newValue is the current update to contentSize - return (old: accumulator.new, new: newValue) - } + anyCancellable = self.publisher(for: \.contentSize, options: [.new]) .sink { [weak self] compare in - if compare.old != compare.new { - self?.invalidateIntrinsicContentSize() - self?.collectionViewHeight?.constant = compare.new.height + guard let self else { return } + if compare.height != self.collectionViewHeight?.constant { + self.invalidateIntrinsicContentSize() + self.collectionViewHeight?.constant = compare.height + self.contentSizeSubject.send(compare) } } } From 59b72835c08b05b2c2012b9f14adc4168ec94a9a Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 11 Mar 2024 13:51:32 -0500 Subject: [PATCH 5/5] include new contentSizePublisher Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift index 7d506961..a51371c2 100644 --- a/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift +++ b/VDS/Components/Buttons/ButtonGroup/ButtonGroup.swift @@ -9,6 +9,7 @@ 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) @@ -98,6 +99,8 @@ open class ButtonGroup: View { buttons.forEach { $0.surface = surface } } } + + open var contentSizePublisher: AnyPublisher { collectionView.contentSizePublisher } //-------------------------------------------------- // MARK: - Private Properties @@ -108,6 +111,7 @@ open class ButtonGroup: View { $0.delegate = self } + /// CollectionView that renders the array of buttonBase obects. fileprivate lazy var collectionView: SelfSizingCollectionView = { return SelfSizingCollectionView(frame: .zero, collectionViewLayout: positionLayout).with {