#StackBounty: #ios #swift #uicollectionview #uicollectionviewcompositionallayout UICollectionViewCompositionalLayout : Dynamic height U…

Bounty: 500

I am able to achieve UICollectionView with dynamic height cell, as shown in the following screenshot. Height of the cell will be automatically adjusted based on content.

enter image description here

Here’s is the code to achieve such outcome.

private func updateListLayout() {
    // Item
    let itemSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .estimated(1)
    )
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
    
    // Group
    let groupSize = itemSize
    //let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 1)
    group.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
    group.interItemSpacing = .fixed(0)
    
    let section = NSCollectionLayoutSection(group: group)
    // Spacing for collection view's leading & trailing & bottom. For top, it is the spacing between header and item
    section.contentInsets = NSDirectionalEdgeInsets(
        top: DashboardViewController.padding * 2,
        leading: DashboardViewController.padding,
        bottom: DashboardViewController.padding * 2,
        trailing: DashboardViewController.padding
    )
    // Vertical spacing between cards within different group.
    section.interGroupSpacing = DashboardViewController.padding
    
    let headerFooterSize = NSCollectionLayoutSize(
        widthDimension: .fractionalWidth(1.0),
        heightDimension: .estimated(1)
    )
    let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
        layoutSize: headerFooterSize,
        elementKind: UICollectionView.elementKindSectionHeader,
        alignment: .top
    )
    section.boundarySupplementaryItems = [sectionHeader]
    
    let compositionalLayout = UICollectionViewCompositionalLayout(section: section)

    // Switch the layout to UICollectionViewCompositionalLayout
    collectionView.collectionViewLayout = compositionalLayout
}

We notice that by using

heightDimension: .estimated(1)

will yield poor performance. It took 2 to 3 seconds, to switch the page tab successfully.

If we change the heightDimension to a higher estimated value, that will increase the performance significantly. It took less than 1 second, to switch the page tab successfully.

heightDimension: .estimated(400)

However, that comes with the following side-effect. Some cards will randomly have an overshot height effect as shown below.

enter image description here

Within a card, we have value 1000 Vertical Content Hugging Priority for the bottom subview. But as you can see in the screenshot, bottom view still try to grow itself to fill up the overshot height.


Our problem right now is

  1. If we are using .estimated(1) for height, we will get correct dynamic height behavior. But, that comes with cost of poor runtime performance.
  2. If we provide a large enough value like .estimated(400) for height, we will get a good runtime performance. However, some card can randomly get an overshoot height effect.

Do anyone know the right way, to achieve UICollectionView with correct dynamic cell height, without impacting runtime performance?


Get this bounty!!!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.