我刚刚遇到了类似的问题,但找到了一个非常不同的解决方案。
我正在使用带有水平滚动的 UICollectionViewFlowLayout 的自定义实现。我还在为每个单元格创建自定义框架位置。
我遇到的问题是 [super layoutAttributesForElementsInRect:rect] 实际上并没有返回应该在屏幕上显示的所有 UICollectionViewLayoutAttributes。在调用 [self.collectionView reloadData] 时,某些单元格会突然被设置为隐藏。
我最终做的是创建一个 NSMutableDictionary,它缓存了我迄今为止看到的所有 UICollectionViewLayoutAttributes,然后包含我知道应该显示的任何项目。
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect];
NSMutableArray * attrs = [NSMutableArray array];
CGSize calculatedSize = [self calculatedItemSize];
[originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) {
NSIndexPath * idxPath = attr.indexPath;
CGRect itemFrame = [self frameForItemAtIndexPath:idxPath];
if (CGRectIntersectsRect(itemFrame, rect))
{
attr = [self layoutAttributesForItemAtIndexPath:idxPath];
[self.savedAttributesDict addAttribute:attr];
}
}];
// We have to do this because there is a bug in the collection view where it won't correctly return all of the on screen cells.
[self.savedAttributesDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray * cachedAttributes, BOOL *stop) {
CGFloat columnX = [key floatValue];
CGFloat leftExtreme = columnX; // This is the left edge of the element (I'm using horizontal scrolling)
CGFloat rightExtreme = columnX + calculatedSize.width; // This is the right edge of the element (I'm using horizontal scrolling)
if (leftExtreme <= (rect.origin.x + rect.size.width) || rightExtreme >= rect.origin.x) {
for (UICollectionViewLayoutAttributes * attr in cachedAttributes) {
[attrs addObject:attr];
}
}
}];
return attrs;
}
这是正确保存 UICollectionViewLayoutAttributes 的 NSMutableDictionary 的类别。
#import "NSMutableDictionary+CDBCollectionViewAttributesCache.h"
@implementation NSMutableDictionary (CDBCollectionViewAttributesCache)
- (void)addAttribute:(UICollectionViewLayoutAttributes*)attribute {
NSString *key = [self keyForAttribute:attribute];
if (key) {
if (![self objectForKey:key]) {
NSMutableArray *array = [NSMutableArray new];
[array addObject:attribute];
[self setObject:array forKey:key];
} else {
__block BOOL alreadyExists = NO;
NSMutableArray *array = [self objectForKey:key];
[array enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *existingAttr, NSUInteger idx, BOOL *stop) {
if ([existingAttr.indexPath compare:attribute.indexPath] == NSOrderedSame) {
alreadyExists = YES;
*stop = YES;
}
}];
if (!alreadyExists) {
[array addObject:attribute];
}
}
} else {
DDLogError(@"%@", [CDKError errorWithMessage:[NSString stringWithFormat:@"Invalid UICollectionVeiwLayoutAttributes passed to category extension"] code:CDKErrorInvalidParams]);
}
}
- (NSArray*)attributesForColumn:(NSUInteger)column {
return [self objectForKey:[NSString stringWithFormat:@"%ld", column]];
}
- (void)removeAttributesForColumn:(NSUInteger)column {
[self removeObjectForKey:[NSString stringWithFormat:@"%ld", column]];
}
- (NSString*)keyForAttribute:(UICollectionViewLayoutAttributes*)attribute {
if (attribute) {
NSInteger column = (NSInteger)attribute.frame.origin.x;
return [NSString stringWithFormat:@"%ld", column];
}
return nil;
}
@end