By default Collection View maintains content offset while inserting cells. On the other hand I'd like to insert cells above the currently displaying ones so that they appear above the screen top edge like Messages.app do when you load earlier messages. Does anyone know the way to achieve it?
This is the technique I use. I've found others cause strange side effects such as screen flicker:
CGFloat bottomOffset = self.collectionView.contentSize.height - self.collectionView.contentOffset.y;
[CATransaction begin];
[CATransaction setDisableActions:YES];
[self.collectionView performBatchUpdates:^{
[self.collectionView insertItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
self.collectionView.contentOffset = CGPointMake(0, self.collectionView.contentSize.height - bottomOffset);
}];
[CATransaction commit];
let amount = 5 // change this to the amount of items to add
let section = 0 // change this to your needs, too
let contentHeight = self.collectionView!.contentSize.height
let offsetY = self.collectionView!.contentOffset.y
let bottomOffset = contentHeight - offsetY
CATransaction.begin()
CATransaction.setDisableActions(true)
self.collectionView!.performBatchUpdates({
var indexPaths = [NSIndexPath]()
for i in 0..<amount {
let index = 0 + i
indexPaths.append(NSIndexPath(forItem: index, inSection: section))
}
if indexPaths.count > 0 {
self.collectionView!.insertItemsAtIndexPaths(indexPaths)
}
}, completion: {
finished in
print("completed loading of new stuff, animating")
self.collectionView!.contentOffset = CGPointMake(0, self.collectionView!.contentSize.height - bottomOffset)
CATransaction.commit()
})
My approach leverages subclassed flow layout. This means that you don't have to hack scrolling/layout code in a view controller. Idea is that whenever you know that you are inserting cells on top you set custom property you flag that next layout update will be inserting cells to top and you remember content size before update. Then you override prepareLayout() and set desired content offset there. It looks something like this:
define variables
private var isInsertingCellsToTop: Bool = false
private var contentSizeWhenInsertingToTop: CGSize?
override prepareLayout()
and after calling super
if isInsertingCellsToTop == true {
if let collectionView = collectionView, oldContentSize = contentSizeWhenInsertingToTop {
let newContentSize = collectionViewContentSize()
let contentOffsetY = collectionView.contentOffset.y + (newContentSize.height - oldContentSize.height)
let newOffset = CGPointMake(collectionView.contentOffset.x, contentOffsetY)
collectionView.setContentOffset(newOffset, animated: false)
}
contentSizeWhenInsertingToTop = nil
isInsertingMessagesToTop = false
}
I did this in two lines of code (although it was on a UITableView) but I think you'd be able to do it the same way.
I rotated the tableview 180 degrees.
Then I rotated each tableview cell by 180 degrees also.
This meant that I could treat it as a standard top to bottom table but the bottom was treated like the top.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With