I'm using UICollectionReusableView
as a header of UICollectionView
section. I enabled "sticky headers" with:
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.sectionHeadersPinToVisibleBounds = true
I'm inserting new sections to collection with:
collectionView.performBatchUpdates({
self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1))
}, completion: nil)
If the insertion happens when collection is overscrolled (bounce is enabled), header will disappear for while (see GIF below). How can I avoid this behaviour?
I am using iOS 12.1.4 but same issue happens also on iOS 11.x and 12.x simulators.
The problem doesn't happen if bounce effect is turned off but I want to keep it on for smoother scroll feeling. I tried invalidate layout before/after update with no result. Thanks for advices.
EDIT (02/26/2019)
Workaround: Wrapping the insertion to performWithoutAnimation
block solve header disappearing but obviously disable reload animation.
UIView.performWithoutAnimation {
collectionView.performBatchUpdates({
self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1))
}, completion: nil)
}
Unfortunately, by calling performBatchUpdates, the layout automatically animates all items itself. Even until now, there's no way to explicitly tell which items to animate and which not to.
However, I came up with a resolution which is kind of an anti-pattern.
For your header class, override these methods:
-(void)setBounds:(CGRect)bounds
{
[CATransaction begin];
[CATransaction setDisableActions:self.shouldDisableAnimations];
[super setBounds:bounds];
[CATransaction commit];
}
//-(void)setCenter:(CGPoint)center
- (void)setCenter:(CGPoint)center
{
[CATransaction begin];
[CATransaction setDisableActions:self.shouldDisableAnimations];
[super setCenter:center];
[CATransaction commit];
}
Now if shouldDisableAnimations is true, the collectionView's automatic animations won't be applied to our header.
However, disabling the animations for the header may cause other glitches (e.g. when you scroll down a lot, and then remove all the cells. the header will jump to top instantly and the collectionView will scroll to top with animation resulting in a glitch!)
To handle this we need to set shouldDisableAnimations for the header in the correct time which is when prepareForCollectionViewUpdates gets called. Unfortunately, we cannot do this through the header's attribute since the attributes are applied to the header after animation gets finished. So we need to make direct access to the header's instance directly from within prepareForCollectionViewUpdates method. (there are several ways to do this. I did this by keeping a weak reference of the header on a class property of itself)
-(void)prepareForCollectionViewUpdates:(NSArray<UICollectionViewUpdateItem *> *)updateItems
{
// Keep track of insert and delete index paths
[super prepareForCollectionViewUpdates:updateItems];
[self.indexPaths2Delete removeAllObjects];
[self.indexPaths2Insert removeAllObjects];
for (UICollectionViewUpdateItem *update in updateItems)
{
if (update.updateAction == UICollectionUpdateActionDelete)
{
[self.indexPaths2Delete addObject:update.indexPathBeforeUpdate];
}
else if (update.updateAction == UICollectionUpdateActionInsert)
{
[self.indexPaths2Insert addObject:update.indexPathAfterUpdate];
}
}
if (self.indexPaths2Insert.count > 0 || self.indexPaths2Delete.count > 0)
{
HomeHeaderView.liveInstance.shouldDisableAnimations = false; //since it may cause scrolling, we should enable the animations
}
else
HomeHeaderView.liveInstance.shouldDisableAnimations = true; //there's nothing added or deleted, so keep the header sticked.
}
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