5

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)
}
4

3 回答 3

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 为真,collectionView 的自动动画将不会应用到我们的标题。

但是,禁用标题的动画可能会导致其他故障(例如,当您向下滚动很多,然后删除所有单元格时。标题将立即跳转到顶部,并且 collectionView 将滚动到顶部动画导致故障!)

为了处理这个问题,我们需要在调用 prepareForCollectionViewUpdates 的正确时间为 header 设置 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.
}

于 2019-10-01T09:43:36.873 回答
0

我之前提供的上述解决方案似乎不适用于 iOS 13。

在 performBatchUpdates 期间,UICollectionView 不会为元素应用 layoutAttributes。解决此问题的唯一方法是在布局的 prepare() 方法中显式设置标题上的框架(或任何其他参数)。因为正在执行一个正在进行的动画,所以 UICollectionView 在动画期间不会布局。

我认为Apple必须添加一个功能来明确标记哪些元素参与动画,哪些不参与。这可以通过元素的 layoutAttributes 或 UICollectionViewLayout 中的单独方法来完成。

从布局访问元素实例是禁忌!但目前没有其他解决方法。

于 2020-01-22T19:26:11.027 回答
0

我也遇到了同样的问题,但我所做的工作是重新加载collectionView(粘性标题没有消失)它自己而不是插入。

于 2020-03-02T08:54:23.330 回答