Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionViewCompositionalLayout bug on iOS 14.3

I'm experiencing a weird layout issue on iOS 14.3 with collection views using a UICollectionViewCompositionalLayout combined in my case with the UICollectionViewDiffableDataSource. The issue is about the wrong position of the inner _UICollectionViewOrthogonalScrollerEmbeddedScrollView when you have an orthogonal section preceded by an intrinsic height section.

Fortunately I'm able to reproduce the issue very easily. Consider having this data source:

private var dataSource: UICollectionViewDiffableDataSource<Section, String>!

enum Section: Int, Hashable, CaseIterable {
    case first = 0
    case second = 1
}

For each section you create the following layout:

private extension Section {
    var section: NSCollectionLayoutSection {
        switch self {
        case .first:
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .estimated(50))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            let section: NSCollectionLayoutSection = .init(group: group)
            return section
        case .second:
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
            let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(200), heightDimension: .absolute(200))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
            let section: NSCollectionLayoutSection = .init(group: group)
            section.orthogonalScrollingBehavior = .continuous
            section.contentInsets = .init(top: 10, leading: 10, bottom: 10, trailing: 10)
            section.interGroupSpacing = 10
            return section
        }
    }
}

The thing breaking the layout is having into the .first section both itemSize and groupSize with .estimated height.

You can see the result below on iOS 14.3: at the first glance the layout is visually correct, but you immediately realize the fact that it's broken because the inner scroll view is in the wrong place. This implies that the horizontal scroll happens wrongly in the blue area.

Broken layout iOS 14.3

Running exactly the same code up to iOS 14.2 you get the correct layout . Correct Layout

What do you think about this issue? Am I missing something or it could be a UIKit bug?

Thanks

like image 396
alfogrillo Avatar asked Dec 19 '20 11:12

alfogrillo


2 Answers

We have header with estimated height and some sections with _UICollectionViewOrthogonalScrollerEmbeddedScrollView were completely broken because of this regression. So here is a solution that worked in our case

public final class CollectionView: UICollectionView {
    
    public override func layoutSubviews() {
        super.layoutSubviews()
    
        guard #available(iOS 14.3, *) else { return }
    
        subviews.forEach { subview in
            guard
                let scrollView = subview as? UIScrollView,
                let minY = scrollView.subviews.map(\.frame.origin.y).min(),
                minY > scrollView.frame.minY
            else { return }
    
            scrollView.contentInset.top = -minY
            scrollView.frame.origin.y = minY
        }
    }
}
like image 68
sftnhrd Avatar answered Sep 18 '22 09:09

sftnhrd


For me this problem is reproducible in iOS 14.3 and 14.4 . And now is fixed in iOS 14.5 beta1

Try to install the latest Xcode beta version 12.5 beta and test it using a simulator running iOS 14.5

Xcode beta link: https://developer.apple.com/download/

like image 42
Marwen Doukh Avatar answered Sep 21 '22 09:09

Marwen Doukh