NEW: Start my new Ultimate Portfolio App course with a free Hacking with Swift+ trial! >>

CollectionView Diffable Data Source scrolling unexpectedly

Forums > Swift

My app displays comments, and users can like these comments. The app uses a diffable data source, and when I click on the last row to like the comment, the collection view scrolls to the centre.

Here is a video of the issue https://streamable.com/9vijyx (sorry about he music, my baby daughter was dancing)

Here is some of my code that I think is relevant - you'll see by the comments that I have tried to fix this issue by storing the content offset but it feels VERY hacky. Any help would be greatly appreciated.

    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() {
        //Any updates to the snapshot, including likes, will
        //scroll the collectionView, but we want to stay on the cell
        // the user has liked, not scroll, so we store the offset.
        //This is then restored after all updates are complete.

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

    func handleCommentLike(cell: PostDetailCell) {
        print("handle like comment")
        guard let indexPath = self.collectionView.indexPath(for: cell) else { return }

        if self.userComments[indexPath.row].like == nil {
            let userId = user.id
            let postId = feedItem.post.id
            let commentId = self.userComments[indexPath.row].comment.id
            let timestamp = Int(Date().timeIntervalSince1970)

            let commentLike = CommentLike(postId: postId, userId: userId, commentId: commentId, createdTimestamp: timestamp)

            self.viewModel.createLike(commentLike: commentLike) { result in
                switch result {
                case .success(let commentLike):
                    print("\(commentLike)")
                    //
                    self.userComments[indexPath.row].like = commentLike
                    self.applySnapshot()
                case .failure(let error):
                    print("Error creating like: \(error)")
                }
            }
        } else {

            guard let like = self.userComments[indexPath.row].like else { return }
            self.viewModel.un(commentLike: like) { result in
                switch result {
                case .success(let like):
                    print(like)
                    self.userComments[indexPath.row].like = nil
                    self.applySnapshot()
                case .failure(let error):
                    print(error)
                }
            }
        }
    }

   

Hey there, I got your source code from upwork and the problem is with your PostDetail model.

You should change

struct PostDetail {
    let identifier = UUID()
    var comment: Comment
    var like: CommentLike?
    var user: User
}

TO

class PostDetail {
    let identifier = UUID()
    var comment: Comment
    var like: CommentLike?
    var user: User

    init(comment: Comment, like: CommentLike? = nil, user: User) {
        self.comment = comment
        self.like = like
        self.user = user
    }
}

And change the rest of you code accordingly. You should also remove updateSnapshot and just use applySnapshot

Cheers.

   

Another possibility would be to just update the cell directly and don't rely on snapshot for this simple change. Without snapshot, you could get reference to the cell from the collection view and set it to like state.

   

Hacking with Swift is sponsored by RevenueCat

SPONSORED Building and maintaining in-app subscription infrastructure is hard. Luckily there's a better way. With RevenueCat, you can implement subscriptions for your app in hours, not months, so you can get back to building your app.

Try it for free

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.