【问题标题】:UICollectionView sticky header disappears for while after inserting section when collection is overscrolled (bounce effect)UICollectionView 粘性标题在集合过度滚动时插入部分后消失一段时间(反弹效果)
【发布时间】:2019-07-18 22:18:41
【问题描述】:

我使用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 模拟器上。

如果关闭反弹效果,则不会发生此问题,但我想保持打开状态以获得更流畅的滚动感觉。我在更新之前/之后尝试使布局无效,但没有结果。感谢您的建议。

编辑(2019 年 2 月 26 日)
解决方法:将插入包装到 performWithoutAnimation 块解决标题消失但显然禁用重新加载动画。

UIView.performWithoutAnimation {
    collectionView.performBatchUpdates({
        self.collectionView.insertSections(IndexSet(integersIn: collectionView.numberOfSections...viewModel.numberOfSections - 1))
    }, completion: nil)
}

【问题讨论】:

    标签: ios swift uicollectionview uicollectionreusableview uicollectionviewflowlayout


    【解决方案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 的自动动画将不会应用到我们的 header。

    但是,禁用标题的动画可能会导致其他故障(例如,当您向下滚动很多,然后删除所有单元格时。标题将立即跳转到顶部,并且 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.
    }

    【讨论】:

      【解决方案2】:

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

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

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

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-11-12
          • 2016-01-14
          • 1970-01-01
          • 2017-07-14
          • 2021-01-09
          • 1970-01-01
          相关资源
          最近更新 更多