2

I have a problem while switching compositional layouts to activate and deactivate orthogonal scrolling makes the cells disappear.

Here is a video:

Cells disappearing

I use exactly the same layout except for orthogonal scrolling:

section.orthogonalScrollingBehavior = hasOrthogonalScroll ? .groupPagingCentered : .none

And I switch the layout with this line:

collectionView.setCollectionViewLayout(layout, animated: true)

The first switch works, but when I switch back, cells disappear...

If someone can tell me what I do wrong, it would be much appreciated...

Here is the full code copy and paste in the ViewController file of a new project:

class ViewController: UIViewController, UICollectionViewDelegate {

    var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionLayout(hasOrthogonalScroll: false))
        collectionView.delegate = self
        collectionView.frame = view.bounds
        collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        view.addSubview(collectionView)
        
        setupDataSource()
    }

    private func collectionLayout(hasOrthogonalScroll: Bool) -> UICollectionViewLayout {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalWidth(0.2))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = hasOrthogonalScroll ? .groupPagingCentered : .none

        return UICollectionViewCompositionalLayout(section: section)
    }
    
    enum Section {
        case main
    }
    
    private var dataSource: UICollectionViewDiffableDataSource<Section, Int>!

    private func setupDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> { (cell, indexPath, identifier) in
            var configuration = cell.defaultContentConfiguration()
            configuration.text = identifier.description
            
            cell.contentConfiguration = configuration
            
            var backgroundConfiguration = cell.backgroundConfiguration
            backgroundConfiguration?.backgroundColor = .secondarySystemBackground
            backgroundConfiguration?.cornerRadius = 8
            backgroundConfiguration?.backgroundInsets = .init(top: 4, leading: 4, bottom: 4, trailing: 4)
            
            cell.backgroundConfiguration = backgroundConfiguration
        }
        
        dataSource = UICollectionViewDiffableDataSource<Section, Int>(collectionView: collectionView) { collectionView, indexPath, identifier in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
        }
        
        var snapshot = NSDiffableDataSourceSnapshot<Section, Int>()
        snapshot.appendSections([.main])
        snapshot.appendItems(Array(1...100))
        dataSource.apply(snapshot, animatingDifferences: false)
    }
    
    var hasOrthogonalScroll = false
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        collectionView.deselectItem(at: indexPath, animated: true)
        
        hasOrthogonalScroll.toggle()
        let layout = collectionLayout(hasOrthogonalScroll: hasOrthogonalScroll)
        collectionView.setCollectionViewLayout(layout, animated: true) 
    }
}
Zaphod
  • 6,758
  • 3
  • 40
  • 60
  • Probably a content offset problem - check https://stackoverflow.com/a/68119885/14351818 and https://stackoverflow.com/q/68788545/14351818 – aheze Jun 06 '22 at 16:26
  • Unfortunately the `contentOffset` never changes. When I inspect cells they are positioned correctly, but not visible, even in the debug view hierarchy. They just seem to disappear... Besides, when I scroll down then up, they correctly reappear. Moreover I have the same problem without the animation. @aheze have you tried it yourself? – Zaphod Jun 07 '22 at 10:05
  • @Zaphod - this is very possibly a bug introduced in iOS 14 (https://developer.apple.com/forums/thread/663449) ... do you need the animation between layouts? – DonMag Jun 08 '22 at 19:50
  • Yes this is the whole purpose, to have the animations... Unfortunately, it seems you are right. (And by the way, when I set the animation to false, the problem is still here, and the only way to have the cells to reappear is to call `reloadData` that is exactly what I try to avoid) – Zaphod Jun 09 '22 at 06:43
  • @Zaphod - the more I play around with it, the more I believe it's either a bug ... or, it's due to a change in the way UIKit manages the cells (in an effort to improve performance). Your example uses 100 items in your data source... any chance your **actual** use case might have a max of, say, 20 items? – DonMag Jun 09 '22 at 12:13
  • @DonMag unfortunately the problem remains the same whatever the cell count is. I've tried 3, 10, 1000 and even only 1... And nothing changes. Moreover the problem is still here in the first beta of iOS 16 and Xcode 14, except that the cells reappear after the animation. But during the animation, they're gone... – Zaphod Jun 09 '22 at 12:38
  • @Zaphod - I asked because, if your "max items" is a reasonably small number, my suggestion would be to use a UI structure other than a collection view. – DonMag Jun 09 '22 at 12:44
  • @DonMag oh sorry... I didn't catch your suggestion. The idea was to let the system work for itself, but indeed it seems I'm going to have to manage it myself... – Zaphod Jun 09 '22 at 12:56

0 Answers0