I have two UICollectionView
s, UICV1
which has UICV2
nested within one of its cells. What I want is that UICV2
self-sizes according to its content, but both the contentSize
and collectionViewLayout.collectionViewContentSize
is zero
.
This exact same setup worked before, the only difference is that UICV2
was a UITableView
. Due to code refactoring and reuse, I switched to using UICollectionView
. The new view hierarchy looks something like that:
+--------------------+
| UICV1 |
| +----------------+ |
| | Cell | |
| | +------------+ | |
| | | Stack View | | |
| | | +--------+ | | |
| | | | UICV2 | | | |
| | | +--------+ | | |
| | +------------+ | |
| +----------------+ |
| ... |
+--------------------+
Both collection views are configured with a UICollectionViewCompositionalLayout
:
// UICV1
let layout1 = UICollectionViewCompositionalLayout { sectionIndex, layoutEnvironment in
let itemSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .estimated(100)
)
let item = NSCollectionLayoutItem(layoutSize: itemSize)
let group = NSCollectionLayoutGroup.horizontal(
layoutSize: itemSize,
subitem: item,
count: 1
)
return NSCollectionLayoutSection(group: group)
}
// UICV2
let layout2 = UICollectionViewCompositionalLayout.list(using: {
var configuration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
configuration.headerMode = .none
configuration.headerTopPadding = 0
return configuration
}())
let collectionView = SelfSizingCollectionView(
frame: .zero,
collectionViewLayout: layout2
)
This is the code for the self sizing collection view:
class SelfSizingCollectionView: UICollectionView {
override init(frame: CGRect, collectionViewLayout layout: UICollectionViewLayout) {
super.init(frame: frame, collectionViewLayout: layout)
isScrollEnabled = false
contentInsetAdjustmentBehavior = .never
}
override var contentSize: CGSize {
didSet {
invalidateIntrinsicContentSize()
}
}
override func layoutSubviews() {
super.layoutSubviews()
invalidateIntrinsicContentSize()
}
override var intrinsicContentSize: CGSize {
layoutIfNeeded()
// This is always (0.0, 0.0)
return CGSize(
width: UIView.noIntrinsicMetric,
height: collectionViewLayout.collectionViewContentSize.height
)
}
}
I am using a NSDiffableDataSourceSnapshot
for providing data to both collection views, if this makes any difference.
I hope someone could help me here, I'm totally lost after playing with combinations of invalidateLayout()
, setNeedsLayout()
and layoutIfNeeded()
at various points within SelfSizingCollectionView
.
I found a ton of answers regarding self-sizing collection views, which I incorporated into my code, but they don't seem to work for the quite new UICollectionViewCompositionalLayout
.
I've fixed it for now by passing the initial bounds to the SelfSizingCollectionView
. Don't know if this comes with caveats or any unforeseen side effects but works for now.
let collectionView = SelfSizingCollectionView(
frame: bounds,
collectionViewLayout: layout2
)