Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop Diffable Data Source scrolling to top after refresh

How can I stop a diffable data source scrolling the view to the top after applying the snapshot. I currently have this...

    fileprivate func configureDataSource() {
        self.datasource = UICollectionViewDiffableDataSource<Section, PostDetail>(collectionView: self.collectionView) {
            (collectionView: UICollectionView, indexPath: IndexPath, userComment: PostDetail) -> UICollectionViewCell? in
            guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PostDetailCell.reuseIdentifier, for: indexPath) as? PostDetailCell else { fatalError("Cannot create cell")}
            
            cell.user = self.user
            cell.postDetail = userComment
            cell.likeCommentDelegate = self
            return cell
        }
        
        var snapshot = NSDiffableDataSourceSnapshot<Section, PostDetail>()
        snapshot.appendSections([.main])
        snapshot.appendItems(self.userComments)
        self.datasource.apply(snapshot, animatingDifferences: true)
    }

    fileprivate func applySnapshot() {

        //let contentOffset = self.collectionView.contentOffset
        var snapshot = NSDiffableDataSourceSnapshot<Section, PostDetail>()
        snapshot.appendSections([.main])
        snapshot.appendItems(self.userComments)
        self.datasource.apply(snapshot, animatingDifferences: false)
        //self.collectionView.contentOffset = contentOffset
    }

store the offset, then reapply it. Sometimes it works perfectly and sometimes the view jumps. Is there a better way of doing this?

like image 384
mickeysox Avatar asked May 09 '26 18:05

mickeysox


2 Answers

The source of this problem is probably your Item identifier type - the UserComment.

Diffable data source uses the hash of your item identifier type to detect if it is a new instance or an old one which is represented currently. If you implement Hashable protocol manually, and you use a UUID which is generated whenever a new instance of the type is initialized, this misguides the Diffable data source and tells it this is a new instance of item identifier. So the previous ones must be deleted and the new ones should be represented. This causes the table or collection view to scroll after applying snapshot. To solve that replace the uuid with one of the properties of the type that you know is unique or more generally use a technique to generate the same hash value for identical instances.

So to summarize, the general idea is to pass instances of the item identifiers with the same hash values to the snapshot to tell the Diffable data source that these items are not new and there is no need to delete previous ones and insert these ones. In this case you will not encounter unnecessary scrolls.

like image 85
Justin Avatar answered May 12 '26 07:05

Justin


First up: in most cases @Amirrezas answer will be the correct reason for the problem. In my case it was not the item, but the section identifier that caused the problem. That was Hashable and Identifiable with correct values, but it was a class, and therefore the hash functions were never called. Took me a while to spot that problem. Changing to a struct (and therefore adopting some things ;) ) helped in my case.

For reference here's a link to the topic on the Apple-Dev forums: https://developer.apple.com/forums/thread/657499

Hope my answer helps somebody :)

like image 23
Georg Avatar answered May 12 '26 07:05

Georg