DatForis DatForis - 1 month ago 19
iOS Question

UICollectionView not scrolling to bottom on the first few items



I've been trying to create a chat interface that I can reuse. I'm almost done with the implementation, but there's something that keeps bugging me about it. If I start loading in messages like in the gif when I first load the interface you can see that after the 4th message there are 3 messages that don't scroll to the bottom. With the 8th being the first one that does finally scroll. This varies according to the screen size. On the iPhone 6s testing device it reaches the 9th message being the one that scrolls.

I'm using content inset as the method to keep the collectionview visible with the following code being run every time the frame of the UIToolbar at the bottom changes

toolBar.inputAccessoryViewFrameChanged = {(rect: CGRect) in Void()
let navigationAndStatusHeight = self.navigationController != nil && self.navigationController!.navigationBar.isTranslucent ? self.navigationController!.navigationBar.frame.size.height + UIApplication.shared.statusBarFrame.height : 0
self.collectionView.contentInset = UIEdgeInsets(top: navigationAndStatusHeight + 8, left: 8, bottom: UIScreen.main.bounds.height - rect.origin.y + 8, right: 8)
self.collectionView.scrollIndicatorInsets.bottom = UIScreen.main.bounds.height - rect.origin.y
}


This code is run every time a new message is inserted:

func insertNewMessage(){
self.collectionView.performBatchUpdates({
self.collectionView.insertItems(at: [NSIndexPath(item: self.numberOfMessages() - 1, section: 0) as IndexPath])
}) { (Bool) in
self.scrollToBottom(animated: true)
}
}


with the scrollToBottom function being:

func scrollToBottom(animated: Bool){
guard self.numberOfMessages() > 0 else{
return
}
self.collectionView.scrollToItem(at: IndexPath(item: self.numberOfMessages() - 1, section: 0), at: UICollectionViewScrollPosition.top , animated: animated)
}


I'm currently running on this version of XCode Version 8.1 beta (8T29o) & iOS 10.1(14B55c)

Answer

The problem maybe when the collection view content size is too small, scrollToItem doesn't work properly. Try use this code

func scrollToBottomAnimated(animated: Bool) {
        guard self.collectionView.numberOfSections > 0 else{
            return
        }

        let items = self.collectionView.numberOfItems(inSection: 0)
        if items == 0 { return }

        let collectionViewContentHeight = self.collectionView.collectionViewLayout.collectionViewContentSize.height
        let isContentTooSmall: Bool = (collectionViewContentHeight < self.collectionView.bounds.size.height)

        if isContentTooSmall {
            self.collectionView.scrollRectToVisible(CGRect(x: 0, y: collectionViewContentHeight - 1, width: 1, height: 1), animated: animated)
            return
        }

        self.collectionView.scrollToItem(at: NSIndexPath(item: items - 1, section: 0) as IndexPath, at: .bottom, animated: animated)

    }