Search code examples
iosswiftuikit

Animation issue while bouncing UIVCollectionView and reload section at the same time


I have a weird animation issue based on two independent events:

1) Bouncing UICollectionView to the top (as in the video below)

2) Serially inserting sections (using DifferenceKit)

I've already verified that this has nothing to do with Attributes calculating in my custom UICollectionFlowLayout.

Does anyone know how to solve it?

Here is a Video of the issue

UPD:

Here is some code, updating collection:

private func updateCollection() {
        let changeset = StagedChangeset(source: self.previousStage, target: self.viewModels)
        // Guarantee that updateCollection calls from background 
        DispatchQueue.main.sync {
            self.delegate?.refreshCollection(with: changeset, update: { collection in
                self.viewModels = collection
                self.previousStage = collection
            })
        }
    }

Solution

  • Well, since no one suggested a solution, I can offer two solutions that I've researched, with their pros and cons

    Before...

    The problem is detected only when collectionView.contentOffset.y is negative and section inserts.

    Approach 1

    While we scrolling / holding any collection our main thread RunLoop has tracking mode and if iOS receive notification about section inserting, this operation is performed in common mode. It updates immediately, possibly neglecting smoothness. The solution is to use

     RunLoop.current.perform(inModes: [.default]) { /* Perform updates */ } 
    

    The main minus is an escaping block and consequently asynchronous updates. Not so good.

    Approach 2

    Since I can't use async updates in my case I just made that

     func scrollViewDidScroll(_ scrollView: UIScrollView) {
            guard let mode = RunLoop.current.currentMode, mode == .tracking, scrollView.contentOffset.y == 0 else {
                previousOffset = scrollView.contentOffset
                return
            }
            scrollView.setContentOffset(previousOffset, animated: false)
        }
    

    Don't think its brilliant solution but I have no idea how to fix it another way.