【问题标题】:How can UICollectionView supplementary views be inserted or deleted correctlyUICollectionView 补充视图如何正确插入或删除
【发布时间】:2016-07-23 01:29:23
【问题描述】:

小问题:

有没有办法在类似于insertItemsAtIndexPaths: deleteItemsAtIndexPaths: 甚至reloadItemsAtIndexPaths: 方法的performBatchUpdates: 块中添加和删除补充视图,如单元格和部分?

详细解释:

我使用带有部分的UICollectionView。单元格像网格一样布置,每行最多可以有 6 个单元格。如果单元格的总数没有填满一个部分的所有行,我会添加额外的补充视图。额外的补充视图只是填补了空白。所以结果应该是每个部分都完全填充了所有可用的单元格,并且(可能的)剩余的空白点填充了补充视图。所以每行有 6 个视觉元素,一个单元格或一个补充视图。

为了实现这一点,我使用以下prepareLayout: 实现实现了一个基于UICollectionViewFlowLayout 的自定义布局:

- (void)prepareLayout {
    [super prepareLayout];

    self.supplementaryViewAttributeList = [NSMutableArray array];
    if(self.collectionView != nil) {
        // calculate layout values
        CGFloat contentWidth = self.collectionViewContentSize.width - self.sectionInset.left - self.sectionInset.right;
        CGFloat cellSizeWithSpacing = self.itemSize.width + self.minimumInteritemSpacing;
        NSInteger numberOfItemsPerLine = floor(contentWidth / cellSizeWithSpacing);
        CGFloat realInterItemSpacing = (contentWidth - (numberOfItemsPerLine * self.itemSize.width)) / (numberOfItemsPerLine - 1);

        // add supplementary attributes
        for (NSInteger numberOfSection = 0; numberOfSection < self.collectionView.numberOfSections; numberOfSection++) {
            NSInteger numberOfItems = [self.collectionView numberOfItemsInSection:numberOfSection];
            NSInteger numberOfSupplementaryViews = numberOfItemsPerLine - (numberOfItems % numberOfItemsPerLine);

            if (numberOfSupplementaryViews > 0 && numberOfSupplementaryViews < 6) {
                NSIndexPath *indexPathOfLastCellOfSection = [NSIndexPath indexPathForItem:(numberOfItems - 1) inSection:numberOfSection];
                UICollectionViewLayoutAttributes *layoutAttributesOfLastCellOfSection = [self layoutAttributesForItemAtIndexPath:indexPathOfLastCellOfSection];

                for (NSInteger numberOfSupplementor = 0; numberOfSupplementor < numberOfSupplementaryViews; numberOfSupplementor++) {
                    NSIndexPath *indexPathOfSupplementor = [NSIndexPath indexPathForItem:(numberOfItems + numberOfSupplementor) inSection:numberOfSection];
                    UICollectionViewLayoutAttributes *supplementaryLayoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:ARNCollectionElementKindFocusGuide withIndexPath:indexPathOfSupplementor];
                    supplementaryLayoutAttributes.frame = CGRectMake(layoutAttributesOfLastCellOfSection.frame.origin.x + ((numberOfSupplementor + 1) * (self.itemSize.width + realInterItemSpacing)), layoutAttributesOfLastCellOfSection.frame.origin.y, self.itemSize.width, self.itemSize.height);
                    supplementaryLayoutAttributes.zIndex = -1;

                    [self.supplementaryViewAttributeList addObject:supplementaryLayoutAttributes];
                }
            }
        }
    }
}

如果所有数据从一开始就都可用并且数据没有变化,则此方法非常有用。但是,如果在生命周期内添加和删除数据,它就会惨遭失败。在performBatchUpdates: 中插入和删除单元格会弄乱补充视图。

会发生什么:

对于使用insertItemsAtIndexPaths: 插入的每个单元格,应删除同一indexPath 处的补充视图。此外,对于使用deleteItemsAtIndexPaths: 删除的每个单元格,应在同一indexPath 添加一个新的补充视图。

问题:

我的布局的prepareLayout: 被调用并计算正确的layoutAttributes。但是layoutAttributesForSupplementaryViewOfKind:atIndexPath: 被称为奇怪的indexPaths。具体来说,layoutAttributesForSupplementaryViewOfKind:atIndexPath: 被称为旧的 indexPaths,它已从 supplementaryViewAttributeList 数组中删除!

示例:

在插入新单元格的情况下,prepareLayout: 会正确删除layoutAttributes,但layoutAttributesForSupplementaryViewOfKind:atIndexPath: 仍会因不再可用且已删除的 indexPath 被调用!仅此而已。对于所有其他补充视图,无需额外调用任何其他indexPaths。

为什么 layoutAttributesForSupplementaryViewOfKind:atIndexPath: 调用 indexPaths 不再可用?如何正确删除、插入或重新加载补充视图?我错过了什么?

来源:

完整的源代码可以在这里找到:

自定义布局:https://github.com/sarn/ARNClassicFilms/blob/master/classicFilms/classicFilms/layout/ARNCollectionViewFocusGuideFlowLayout.m

CollectionView 控制器: https://github.com/sarn/ARNClassicFilms/blob/master/classicFilms/classicFilms/view-controllers/ARNMovieOverviewController.mperformBatchUpdates: 在类的最后一个方法中)

【问题讨论】:

  • 嘿,我刚刚看到你的帖子,想知道你有没有发现什么?我遇到了very similar issue
  • 上周我实际上在 WWDC 上询问了一位 Apple 工程师。他提供的解决方案是将[[collectionView collectionViewLayout] invalidateLayout]; 添加到performBatchUpdates: 块中。这实际上适用于我的情况。也许这对您的情况也有帮助
  • 意味着我当时很接近,我在块之前添加了它,如果它有成果,我会尝试更新我的问题。
  • 是的,我尝试添加它,但它仍然没有正确更新补充视图...one of the issues being this

标签: ios objective-c uicollectionview uicollectionviewlayout uicollectionreusableview


【解决方案1】:

您的评论对我来说不是什么诀窍,我找到了另一段代码并添加了它并且它有效,甚至删除了上述建议,它仍然有效。集合视图当然很强大,但忘记了一个功能,比如这个......

- (NSArray<NSIndexPath *>   *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind
{
    return self.removedIndexPaths;
}

事情可能会变得相当糟糕。

【讨论】:

    【解决方案2】:

    一种解决方案是将[[collectionView collectionViewLayout] invalidateLayout] 添加到performBatchUpdates: 块。这会强制布局重新计算并删除无效的 indexPaths。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-24
      • 1970-01-01
      • 1970-01-01
      • 2013-02-20
      • 2015-12-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多