0

I currently have a couple of collection views that use compositional layouts that I'm trying to add to two separate vertical stack views on top of each other. One of my collection view will be going into the headerContentView and the other will be going into the actual contentView.

My collectionView should be self-sizing by invalidating the intrinsic content size. However, for some reason, only one of the collectionView is visible because one will size itself to the content size. However, the other will have a height of 0. As a note, the stack view that contains the second collectionView also has a height of zero.

I need help to have the collection views size properly. Thanks for your time.

StackViews:
internal let contentStackView: UIStackView = {
    let stackView = UIStackView()
    stackView.axis = .vertical
    return stackView
}()
Constraints on StackView:
private func setUpView() {
    backgroundColor = .blue
    layoutMargins = UIEdgeInsets(top: 0, left: 16, bottom: 24, right: 16)

    addSubview(headerView)
    addSubview(contentStackView)

    // Preserve superview layout margins so that sub-elements can be laid out using layoutMarginsGuide
    contentStackView.preservesSuperviewLayoutMargins = true

    [headerView, contentStackView].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
    NSLayoutConstraint.activate([
        headerView.topAnchor.constraint(equalTo: topAnchor),
        contentStackView.topAnchor.constraint(equalTo: headerView.bottomAnchor, constant: 16),
        layoutMarginsGuide.bottomAnchor.constraint(lessThanOrEqualTo: contentStackView.bottomAnchor),

        headerView.leadingAnchor.constraint(equalTo: leadingAnchor),
        headerView.trailingAnchor.constraint(equalTo: trailingAnchor),
        contentStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
        contentStackView.trailingAnchor.constraint(equalTo: trailingAnchor)
    ])
}

private func setUpHeaderView() {
    // Preserve superview layout margins so that sub-elements can be laid out using layoutMarginsGuide
    headerView.preservesSuperviewLayoutMargins = true
    headerContentStackView.preservesSuperviewLayoutMargins = true
    headerView.addSubview(headerContentStackView)

    headerContentStackView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        headerContentStackView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
        headerView.bottomAnchor.constraint(lessThanOrEqualTo: headerContentStackView.bottomAnchor),

        headerContentStackView.leadingAnchor.constraint(equalTo: headerView.leadingAnchor),
        headerContentStackView.trailingAnchor.constraint(equalTo: headerView.trailingAnchor)
    ])

    // Add header contents to header content stack view
    headerContentStackView.addArrangedSubview(headerBarView)
    headerContentStackView.addArrangedSubview(notificationView)
}
Compostional layout:
 private static func generateCompositionalLayout() -> UICollectionViewLayout {
    // Items
    let itemSize: NSCollectionLayoutSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(UIConstantsIconTileCollectionView.PhaseTwo.fractionalWidthForItems),
        heightDimension: .fractionalHeight(UIConstantsIconTileCollectionView.PhaseTwo.fullWidthOrHeight)
    )
    let fullItem: NSCollectionLayoutItem = NSCollectionLayoutItem(layoutSize: itemSize)

    // Groups
    let groupSize: NSCollectionLayoutSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(UIConstantsIconTileCollectionView.PhaseTwo.fullWidthOrHeight),
        heightDimension: .fractionalWidth(UIConstantsIconTileCollectionView.PhaseTwo.fractionalWidthForGroups)
    )
    let group: NSCollectionLayoutGroup = NSCollectionLayoutGroup.horizontal(
        layoutSize: groupSize,
        subitem: fullItem,
        count: UIConstantsIconTileCollectionView.PhaseTwo.numberOfItemsPerGroup
    )
    group.interItemSpacing = .fixed(UIConstantsIconTileCollectionView.PhaseTwo.interGroupSpacing)

    // Section
    let section: NSCollectionLayoutSection = NSCollectionLayoutSection(group: group)
    section.contentInsets = NSDirectionalEdgeInsets(
        top: 0,
        leading: UIConstantsIconTileCollectionView.PhaseTwo.interSectionSpacing,
        bottom: 0,
        trailing: UIConstantsIconTileCollectionView.PhaseTwo.interSectionSpacing
    )

    return UICollectionViewCompositionalLayout(section: section)
}
Self Sizing Collection View:
// MARK: - View Layout
override var contentSize: CGSize {
    didSet {
        invalidateIntrinsicContentSize()
    }
}

override var intrinsicContentSize: CGSize {
    return contentSize
}
Saurav_Sharma
  • 130
  • 1
  • 10
Kwoner
  • 963
  • 1
  • 6
  • 7

1 Answers1

0

My solution to this was the way I was implementing the CollectionViewController. I was overriding the loadView() and replacing the view itself with the collectionView. Example, below:

override func loadView() {
     view = collectionView
}

However, when I override viewDidLoad and add the collectionView as a subview and constraint it to the view controllers view it works out just fine. Example, below:

override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(collectionView)
    // Constraint collectionView -> view
}

I couldn't find why this plays nicer with stackViews because it kind of blows my mind but this solved the issue. If anyone has more knowledge as to WHY essentially just having a container view for the collectionView plays nicely with the stackView I would appreciate the knowledge.

Kwoner
  • 963
  • 1
  • 6
  • 7