UICollectionView补充视图如何正确插入或删除
How can UICollectionView supplementary views be inserted or deleted correctly
小问题:
有没有办法在 performBatchUpdates:
块中添加和删除补充视图,例如单元格和部分,类似于 insertItemsAtIndexPaths:
deleteItemsAtIndexPaths:
甚至 reloadItemsAtIndexPaths:
方法?
详细解释:
我使用带部分的 UICollectionView
。单元格像网格一样布局,每行最多可以有 6 个单元格。如果单元格总数没有填满一个部分的所有行,我会添加额外的补充视图。额外的补充意见正好填补了空白space。所以结果应该是每个部分都被所有可用的单元格完全填充,而(可能的)剩余的空白点被补充视图填充。所以每行有 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:
是为从 supplementaryViewAttributeList
数组中删除的旧 indexPaths
调用的!
示例:
在插入新单元格的情况下,prepareLayout:
正确地删除了 layoutAttributes
,但是 layoutAttributesForSupplementaryViewOfKind:atIndexPath:
仍然会因为不再可用而被调用并删除了 indexPath!仅此而已。没有对所有其他补充视图的任何其他 indexPath
的额外调用。
为什么 layoutAttributesForSupplementaryViewOfKind:atIndexPath:
要求 indexPaths
不再可用?如何正确删除、插入或重新加载补充视图?我想念什么?
来源:
可在此处找到完整的源代码:
集合视图控制器:
https://github.com/sarn/ARNClassicFilms/blob/master/classicFilms/classicFilms/view-controllers/ARNMovieOverviewController.m
(performBatchUpdates:
是在class的最后一个方法)
一个解决方案是在 performBatchUpdates:
块中添加一个 [[collectionView collectionViewLayout] invalidateLayout]
。这会强制布局重新计算并删除无效的 indexPaths。
你的评论对我没有用,我找到了另一段代码并添加了它并且它起作用了,甚至删除了上面的建议,它仍然起作用。集合视图当然很强大,但是忘记了一个功能,比如这个...
- (NSArray<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind
{
return self.removedIndexPaths;
}
而且事情可能会变得相当糟糕。
小问题:
有没有办法在 performBatchUpdates:
块中添加和删除补充视图,例如单元格和部分,类似于 insertItemsAtIndexPaths:
deleteItemsAtIndexPaths:
甚至 reloadItemsAtIndexPaths:
方法?
详细解释:
我使用带部分的 UICollectionView
。单元格像网格一样布局,每行最多可以有 6 个单元格。如果单元格总数没有填满一个部分的所有行,我会添加额外的补充视图。额外的补充意见正好填补了空白space。所以结果应该是每个部分都被所有可用的单元格完全填充,而(可能的)剩余的空白点被补充视图填充。所以每行有 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:
是为从 supplementaryViewAttributeList
数组中删除的旧 indexPaths
调用的!
示例:
在插入新单元格的情况下,prepareLayout:
正确地删除了 layoutAttributes
,但是 layoutAttributesForSupplementaryViewOfKind:atIndexPath:
仍然会因为不再可用而被调用并删除了 indexPath!仅此而已。没有对所有其他补充视图的任何其他 indexPath
的额外调用。
为什么 layoutAttributesForSupplementaryViewOfKind:atIndexPath:
要求 indexPaths
不再可用?如何正确删除、插入或重新加载补充视图?我想念什么?
来源:
可在此处找到完整的源代码:
集合视图控制器:
https://github.com/sarn/ARNClassicFilms/blob/master/classicFilms/classicFilms/view-controllers/ARNMovieOverviewController.m
(performBatchUpdates:
是在class的最后一个方法)
一个解决方案是在 performBatchUpdates:
块中添加一个 [[collectionView collectionViewLayout] invalidateLayout]
。这会强制布局重新计算并删除无效的 indexPaths。
你的评论对我没有用,我找到了另一段代码并添加了它并且它起作用了,甚至删除了上面的建议,它仍然起作用。集合视图当然很强大,但是忘记了一个功能,比如这个...
- (NSArray<NSIndexPath *> *)indexPathsToDeleteForSupplementaryViewOfKind:(NSString *)elementKind
{
return self.removedIndexPaths;
}
而且事情可能会变得相当糟糕。