我使用UICollectionReusableView
作为UICollectionView
部分的标题。我启用了“粘性标头”:
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.sectionHeadersPinToVisibleBounds = true
我要通过以下方式将新部分插入收藏集:
collectionView.performBatchUpdates({
self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1))
}, completion: nil)
如果插入是在集合过度滚动(启用反弹)时发生的,则标头会消失一会儿(请参见下面的GIF)。 如何避免这种行为?
我正在使用iOS 12.1.4,但在iOS 11.x和12.x模拟器上也会发生相同的问题。
如果关闭了弹跳效果,则不会出现此问题,但是我想保持该状态以使滚动感觉更流畅。我尝试在更新之前/之后使布局无效,但没有结果。感谢您的建议。
编辑(02/26/2019)
解决方法:将插入内容包装到performWithoutAnimation
块中可以解决标题消失的问题,但显然会禁用重新加载动画。
UIView.performWithoutAnimation {
collectionView.performBatchUpdates({
self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1))
}, completion: nil)
}
答案 0 :(得分:1)
不幸的是,通过调用performBatchUpdates,布局自动为所有项目本身设置了动画。即使到现在,也没有办法明确指出要动画的项目和不动画的项目。
但是,我想出了一种反模式的解决方案。
对于标题类,请覆盖以下方法:
-(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];
}
现在,如果shouldDisableAnimations为true,则collectionView的自动动画将不会应用于我们的标题。
但是,禁用标题的动画可能会导致其他故障(例如,当您向下滚动很多然后删除所有单元格时。标题将立即跳到顶部,并且collectionView将随着动画滚动到顶部,从而导致小故障!)
要处理此问题,我们需要在调用prepareForCollectionViewUpdates的正确时间内为标头设置shouldDisableAnimations。不幸的是,我们无法通过标题的属性来执行此操作,因为在动画完成后,属性会应用于标题。因此,我们需要直接从prepareForCollectionViewUpdates方法中直接访问标头的实例。 (有几种方法可以做到这一点。我通过在自身的类属性上保留对标头的弱引用来实现此目的)
-(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.
}
答案 1 :(得分:0)
我之前提供的上述解决方案似乎无法在iOS 13上运行。
在performBatchUpdates期间,UICollectionView不会为元素应用layoutAttributes。解决此问题的唯一方法是在版面的prepare()方法内显式设置标头上的框架(或其他参数)。由于正在执行动画,因此UICollectionView不会在动画期间进行布局。
我认为Apple必须添加一项功能,以明确标记哪些元素参与动画,哪些不参与。这可以通过元素的layoutAttributes或UICollectionViewLayout中的单独方法来完成。
从布局访问元素实例是不行的!但是目前没有其他解决方法。
答案 2 :(得分:0)
我也有同样的问题,但是我要做的工作是重新加载而不是插入的collectionView(粘性标头没有消失)。