Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cells disappearing during layout animation #43

Closed
enarity opened this issue Feb 16, 2023 · 5 comments
Closed

Cells disappearing during layout animation #43

enarity opened this issue Feb 16, 2023 · 5 comments
Assignees
Labels
enhancement New feature or request

Comments

@enarity
Copy link

enarity commented Feb 16, 2023

Hi! First of all, thank you for this wonderfully crafted library.

Now, I have an issue that has been haunting me for a long time both in my custom layouts and this ChatLayout. The issue is that during layout animations that would change the viewport of the collection view, the cells that would be out-of-screen by the end of the animation disappear immediately when animation begins. You can see it in the example app if you open the keyboard: cells at the top disappear as soon as the animation begins.

From what I could gather, this happens because the animations that are triggered by the layoutIfNeeded() call (used in restoreContentOffset method) are run out-of-process on the RenderServer and collection view has already done its layout pass by the time the animation begins, thus removing the cells.
There are some workarounds I thought of, like expanding the collection view frame beyond the top edge of the superview, or moving it with a transform, but these seem very hacky.
Have you ever encountered this issue and do you have any ideas on how to fix this?

Simulator.Screen.Recording.-.iPhone.14.-.2023-02-16.at.17.00.00.mp4
@ekazaev ekazaev self-assigned this Feb 20, 2023
@ekazaev
Copy link
Owner

ekazaev commented Feb 20, 2023

@enarity Hi, Thank you.

Yep. I see the same issue and Ive seen it before. And your explanation is they way how I understand the problem. I couldn't find good enough solution for that issue and it looks not so noticeable on the device with the normal animation speed so I considered it to be a necessary evil and dropped fighting it. It was quite some time ago, but as far as I remember changing the content offset itself also causes extra layoutIfNeeded() call so it wasn't a way to go either.

If you will come across a good solution for that issue - please share and Ill add it to the library.

@ekazaev ekazaev added the enhancement New feature or request label Feb 20, 2023
@ekazaev
Copy link
Owner

ekazaev commented Feb 20, 2023

@enarity

Forgot to mention - you can always achieve such result using setContentOffset animated

It is a demo code below but you got the idea. Just replace it in the Example app.

            // Blocks possible updates when keyboard is being hidden interactively
            currentInterfaceActions.options.insert(.changingContentInsets)
            UIView.animate(withDuration: info.animationDuration, animations: {
                self.collectionView.performBatchUpdates({
                    self.collectionView.contentInset.bottom = newBottomInset
                    self.collectionView.scrollIndicatorInsets.bottom = newBottomInset
                }, completion: nil)

                self.collectionView.setContentOffset(CGPoint(x: 0, y: self.collectionView.contentOffset.y + newBottomInset), animated: true)

//                if let positionSnapshot, !self.isUserInitiatedScrolling {
//                    self.chatLayout.restoreContentOffset(with: positionSnapshot)
//                }
                if #available(iOS 13.0, *) {
                } else {
                    // When contentInset is changed programmatically IOs 13 calls invalidate context automatically.
                    // this does not happen in ios 12 so we do it manually
                    self.collectionView.collectionViewLayout.invalidateLayout()
                }

animated_offset

@enarity
Copy link
Author

enarity commented Feb 21, 2023

@ekazaev
Thanks for your reply. This approach is suboptimal because the animation parameters in this case do not match the keyboard animation parameters, and the calculations must be more involved to exactly match the content offset like your restoreContentOffset approach does (see how the bottom edge of the visible content changes after the keyboard appears in your example gif).
I'm still very actively looking for an optimal solution and surely will share if I ever find one.

@ekazaev
Copy link
Owner

ekazaev commented Feb 21, 2023

@enarity The thing that comes to my head is to try something related to CADisplayLink related solution. But it would lay outside of the layout itself. The problem is that set setContentOffset(_ contentOffset: CGPoint, animated: Bool) as soon as you say animated: false it will also call layoutIfNeeded and give you the same effect.

@ekazaev
Copy link
Owner

ekazaev commented Feb 22, 2023

@enarity Ill close this issue as it is not exactly related to the layout itself. But please contact me if youll find a good solution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants