UICollectionView List Layout issue on iOS 14

Viewed 594

I have a problem with the new UICollectionView's list layout on iOS 14.

class ViewController: UICollectionViewController {
    struct Item: Hashable {
        let title: String
        let summary: String
    }
    
    enum Section {
        case main
    }
    
    var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let layoutConfig = UICollectionLayoutListConfiguration(appearance: .plain)
        let listLayout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
        collectionView.setCollectionViewLayout(listLayout, animated: false)
        
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Item> { cell, indexPath, item in
            var content = cell.defaultContentConfiguration()
            content.text = item.title
            content.secondaryText = item.summary
            cell.contentConfiguration = content
            cell.accessories = [.delete()]
        }
        
        dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView) {
            collectionView, indexPath, identifier in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
        }
        
        let items = (0..<100).map {
            Item(title: "Item \($0)", summary: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec id tempor libero. Sed scelerisque mauris quis lacus vulputate, at efficitur neque sollicitudin. Vivamus aliquam dapibus tincidunt. Curabitur iaculis turpis vel lectus commodo aliquam. Nam felis orci, bibendum a felis convallis, scelerisque sollicitudin felis.")
        }
        
        var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
        snapshot.appendSections([.main])
        snapshot.appendItems(items, toSection: .main)
        dataSource.apply(snapshot, animatingDifferences: false)
        
        navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Edit", style: .plain, target: self, action: #selector(edit))
    }
    
    @objc private func edit() {
        collectionView.isEditing.toggle()
    }
}

When I scroll to a cell, such as the cell at index 10, then tap Edit button, the collection view jumps to the cell at index 32.

enter image description here

I tried to subclass collection view cell and specify a fixed height, but it does not help.

class MyCell: UICollectionViewListCell {
    override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
        let attrs = super.preferredLayoutAttributesFitting(layoutAttributes)
        attrs.bounds.size.height = 200
        return attrs
    }
}

This issue does not happen with UITableView (dynamic row height).

Am I missing something? Anyone can help me to solve this issue?

Thanks!

1 Answers

This is happening because when the edit mode is enabled and the delete button is added to the cell, your content grows, you can see your content goes from 6 lines to 7 lines, so your cells grow with it. Try adding a max number of lines to the label and see if it still happens. If you don't want to mess with content size, you could always keep a reference to the collection view contentOffset before the toggle and set it back when on.

Related