UICollectionView粘性标头在插入部分后滚动了一段时间(集合效果过大)时消失了一段时间(反弹效果) [英] UICollectionView sticky header disappears for while after inserting section when collection is overscrolled (bounce effect)

查看:100
本文介绍了UICollectionView粘性标头在插入部分后滚动了一段时间(集合效果过大)时消失了一段时间(反弹效果)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用UICollectionReusableView作为UICollectionView部分的标题.我启用了粘性标头":

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)

如果插入是在集合过度滚动(启用反弹)时发生的,则标头将消失一会儿(请参见下面的GIF). 如何避免这种行为?

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?

我正在使用iOS 12.1.4,但在iOS 11.x和12.x模拟器上也会发生相同的问题.

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.

编辑(02/26/2019)
解决方法:将插入内容包装到performWithoutAnimation块可解决标题消失的问题,但显然会禁用重新加载动画.

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

推荐答案

不幸的是,通过调用performBatchUpdates,布局自动为所有项目设置了动画.即使到现在,也没有办法明确指出要动画的项目和不动画的项目.

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];
        }

现在,如果shouldDisableAnimations为true,则collectionView的自动动画将不会应用于我们的标题.

Now if shouldDisableAnimations is true, the collectionView's automatic animations won't be applied to our header.

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

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!)

要处理此问题,我们需要在正确的时间内(即prepareForCollectionViewUpdates被调用时)为标头设置shouldDisableAnimations.不幸的是,我们无法通过标题的属性来执行此操作,因为属性是在动画完成后应用于标题的.因此,我们需要直接从prepareForCollectionViewUpdates方法中直接访问标头的实例. (有几种方法可以做到这一点.我是通过在其自身的类属性上保留对标头的弱引用来实现的)

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.
}

这篇关于UICollectionView粘性标头在插入部分后滚动了一段时间(集合效果过大)时消失了一段时间(反弹效果)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆