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

CollectionView does not scroll to last item when not visible item #14

Closed
deehegarty opened this issue Apr 8, 2021 · 7 comments
Closed
Assignees
Labels
enhancement New feature or request question Further information is requested

Comments

@deehegarty
Copy link

deehegarty commented Apr 8, 2021

Expected behaviour:
When a user sends a message and taps on the send button, the should be a scroll to the last item in the CollectionView.

Actual behaviour:
When a user sends a message and taps on the send button, the CollectionView will scroll to show the just top of the last item.

It appears to be taking the estimated item size instead of the actual size of the new cell that has just been sent by the end user. The cell is added to the view and can be seen once you manually scroll to the bottom. Example: when we increased the estimated item height to 100, the scrolling was correct, but only for smaller messages. If it was a bigger message, it would be cut off after 100 height.

Something to note is that the above behaviour occurs when animation = true when scrolling i.e. self?.collectionView.setContentOffset(contentOffsetAtBottom, animated: true). When animation = false the CollectionView will scroll to the correct position.

Reproduction steps:

  1. Open conversation
  2. Have at least enough messages where you can scroll up and not see the latest message
  3. Send a message while you are scrolled and can’t see the latest message
  4. See how it scrolls only to the top of the latest message not to the cell itself.

Note: scrollToBottom() is not currently working in the Example app provided

@ekazaev ekazaev self-assigned this Apr 9, 2021
@ekazaev
Copy link
Owner

ekazaev commented Apr 9, 2021

Hi @deehegarty

Thank you for the issue. Can you explain me some details. Current Example app does not scroll to the bottom of the collection view after the new message is sent. Or if it does - it is a side effect of some other action. Is that the issue within your modification?

Actual behaviour:
When a user sends a message and taps on the send button, the CollectionView will scroll to show the just top of the last item.

@ekazaev
Copy link
Owner

ekazaev commented Apr 9, 2021

I should give some details here.
Whatever happens with layout items outside of visible area - they will always have an estimated value. Every collection layout behaves this way. The actual size of the cell will be calculated only at the moment of appearance of the cell. Just imagine the situation when you inserted not just 1 cell but 10000, but all of them are outside of the visible area. It will take severe amount of time to calculate 10000 layouts. But this calculations are completely unnecessary. So you can not rely on collectionView.setContentOffset(WHATEVER, animated: true) as the actual contentOffset of the cell that you expect to reach will be different. During the animated scrolling every cell that appears will be calculated and will change the contentSize. It applies to any collection view layout.

If you require to scroll to some specific cell - you should use func restoreContentOffset(with snapshot: ChatLayoutPositionSnapshot) provided with ChatLayout

So, in the current example app. If you require to scroll to the bottom of the collection view every time user sends a message - it needs to be modified this way:

            self.chatController.sendMessage(.text(messageText)) { sections in
                UIView.animate(withDuration: 0.25, animations: {
                    let positionSnapshot = ChatLayoutPositionSnapshot(indexPath: IndexPath(item: 0, section: 0), kind: .footer, edge: .bottom)
                    self.chatLayout.restoreContentOffset(with: positionSnapshot)
                }, completion: { _ in
                    self.currentInterfaceActions.options.remove(.sendingMessage)
                    self.processUpdates(with: sections, animated: true)
                })
            }

But, be aware: If you are using UIView.animate(...) as suggested, you may face the issues like one described here https://dasdom.dev/posts/scrolling-a-collection-view-with-custom-duration/ and you should implement your own animated scrolling method using CADisplayLink if you want everything to be smooth.

@ekazaev ekazaev added the question Further information is requested label Apr 9, 2021
@ekazaev
Copy link
Owner

ekazaev commented Apr 9, 2021

@deehegarty Please let me know if you are satisfied with the answer. If you have any other question - please do not hesitate to ask.

@deehegarty
Copy link
Author

deehegarty commented Apr 9, 2021

@ekazaev Thanks so much for this information (some really good info here). What I had inside public func inputBar(_ inputBar: InputBarAccessoryView, didPressSendButtonWith text: String) was a call to scrollToBottom() instead of the code snippet you have just provided. I had thought that calling scrollToBottom() at this point would scroll to the last item in the CollectionView. What actually happens is the behaviour that I have described above.

@ekazaev
Copy link
Owner

ekazaev commented Apr 9, 2021

@deehegarty I think its just a misleading name of the method. I use it only to adjust the offset the the size of input view changes, it usually happens within the visible zone, so for me those nuances are not critical. Ill update the Example app to avoid the confusion.

@ekazaev ekazaev added the enhancement New feature or request label Apr 9, 2021
@ekazaev ekazaev closed this as completed Apr 9, 2021
@deehegarty
Copy link
Author

@ekazaev Thanks so much for the clarification 😃

@ekazaev
Copy link
Owner

ekazaev commented Apr 21, 2021

@deehegarty JFYI: The example app was recently updated to demonstrate one of the possible implementations of your request

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

No branches or pull requests

2 participants