滚动时,大的UICollectionViewCell停止显示

UICollectionView行为与UICollectionView所描述的一样,导致了这个问题 。 即使我决定自己发一个,因为我做了进一步的调查,所以我不想发表评论或编辑上面提到的问题。

怎么了?:

当使用UICollectionViewUICollectionView中显示大单元格后,将集合视图滚动到某个偏移量后,单元格将消失。

当进一步滚动直到另一个单元进入可见区域时,消失/隐藏的单元再次变为可见。

我testing了一个垂直滚动收集视图和全宽单元格,但我相当肯定,这也会发生类似的水平滚动设置。

什么是大细胞?

所描述的行为发生在高于显示高度两倍的960.f + 1.f上(3,5英寸显示器上的1136.f + 1.f ,4英寸上的1136.f + 1.f )。

究竟发生了什么?

当集合视图的滚动偏移量超过cell.frame.origin.y + displayHeightOfHardware ,隐藏属性的单元格设置为YES并且-collectionView:didEndDisplayingCell:forItemAtIndexPath:被调用(例如,当scrollingOffset.y达到481.f时,第一个单元格变为隐藏在3,5英寸的iPhone上)。

如上所述,当滚动到下一个单元格进入视图时,隐藏单元格被再次显示(即,隐藏属性改变为NO ),而且,当滚动得足够远时,单元格不会再消失,当它不应该时,无论在何处你滚动到。

处理大于三显示器高度( 1441.f/1705.f )的单元格时会发生此变化。 那些显示相同的行为,但它保持不变,无论他们上下滚动多远。

还有什么?:

情况不能通过重写来解决-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds返回YES

这些单元格不能被强制显示,隐藏后隐藏的属性设置为NO (例如在didEndDisplayingCell中)

那么,这个问题是什么?

我很肯定,这是UICollectionView/Controller/Cell/Layout一个错误,我将在Apple提交一个TSI。 但同时: 有没有人有任何想法快速黑客解决scheme

我有这个问题非常肮脏和内部的解决scheme:

 @interface UICollectionView () - (CGRect)_visibleBounds; @end @interface MyCollectionView : UICollectionView @end @implementation MyCollectionView - (CGRect)_visibleBounds { CGRect rect = [super _visibleBounds]; rect.size.height = [self heightOfLargestVisibleCell]; return rect; } - (float)heightOfLargestVisibleCell { // do your calculations for current max cellHeight and return it return 1234; } @end 

我有一个解决方法,似乎为我工作,不应该运行苹果的iOS应用程序的规则。

关键是观察到大单元格边界是问题。 我已经解决了这个问题,确保单元格的一个边缘位于可滚动内容区域的可视区域内。 您显然需要根据您的需要inheritanceUICollectionViewFlowLayout类或UICollectionViewLayout,并使用contentOffset值来跟踪您在UIScrollView中的位置。

我还必须确保:

 - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 

返回YES或面临表示布局无效的运行时exception。 在我的情况下,我保留更大的单元格的边缘绑定到左边缘。 这样可以避免对这些较大的单元格进行错误的边界交集检测。

这确实会创build更多的工作,具体取决于在滚动时更新单元格的宽度/高度时,如何渲染单元格的内容。 在我的情况下,单元格内的子视图相对简单,不需要太多的摆弄。

按照要求这里是我的layoutAttributesInRect一个例子

 - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSMutableArray* attributes = [NSMutableArray array]; NSArray *vertical = myVerticalCellsStore.cells; NSInteger startRow = floor(rect.origin.y * (vertical.count)/ (vertical.count * verticalViewHeight + verticalViewSpacing * 2)); startRow = (startRow < 0) ? 0 : startRow; for (NSInteger i = startRow; i < vertical.count && (rect.origin.y + rect.size.height >= i * verticalViewHeight); i++) { NSArray *horizontals = myHorizontalStore.horizontalCells; UICollectionViewLayoutAttributes *verticalAttr = [self layoutAttributesForSupplementaryViewOfKind:@"vertical" atIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]]; if (CGRectIntersectsRect(verticalAttr.frame, rect)) { [attributes addObject:verticalAttr]; } BOOL foundAnElement = NO; for (NSInteger j = 0 ; j < horizontals.count; j++) { MYViewLayoutAttributes *attr = (MyViewLayoutAttributes *)[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]]; if (CGRectIntersectsRect(rect, attr.frame)) { [attributes addObject: attr]; foundAnElement = YES; } else if (foundAnElement) { break; } } } return attributes; } 

这是我的消毒代码。 基本上我计算的是第一个细胞应该基于细胞高度。 在我的情况下是固定的,所以计算相当简单。 但我的水平元素有不同的宽度。 所以内部循环实际上是找出要包含在属性数组中的正确数量的水平单元。 在那里,我使用CGRectIntersectsRect来确定单元格是否相交。 然后循环继续下去,直到交集失败。 如果至less有一个水平单元已经find,则循环将会中断。 希望有所帮助。

我的解决scheme与Jonathan基本相同,但在一个类别中,所以您不必使用自己的子类。

 @implementation UICollectionView (MTDFixDisappearingCellBug) + (void)load { NSError *error = nil; NSString *visibleBoundsSelector = [NSString stringWithFormat:@"%@isib%@unds", @"_v",@"leBo"]; if (![[self class] swizzleMethod:NSSelectorFromString(visibleBoundsSelector) withMethod:@selector(mtd_visibleBounds) error:&error]) { FKLogErrorVariables(error); } } - (CGRect)mtd_visibleBounds { CGRect bounds = [self mtd_visibleBounds]; // swizzled, no infinite loop MTDDiscussCollectionViewLayout *layout = [MTDDiscussCollectionViewLayout castedObjectOrNil:self.collectionViewLayout]; // Don`t ask me why, but there's a visual glitch when the collection view is scrolled to the top and the max height is too big, // this fixes it if (bounds.origin.y <= 0.f) { return bounds; } bounds.size.height = MAX(bounds.size.height, layout.maxColumnHeight); return bounds; } @end 

我发现这个问题只发生在使用子类UICollectionViewLayoutAttributes时,并且该属性类没有正确的isEqual:方法。

举个例子:

 @implementation COGridCollectionViewLayoutAttributes - (id)copyWithZone:(NSZone *)zone { COGridCollectionViewLayoutAttributes *attributes = [super copyWithZone:zone]; attributes.isInEditMode = _isInEditMode; return attributes; } - (BOOL)isEqual:(id)other { if (other == self) { return YES; } if (!other || ![[other class] isEqual:[self class]]) { return NO; } if ([((COGridCollectionViewLayoutAttributes *) other) isInEditMode] != [self isInEditMode]) { return NO; } return [super isEqual:other]; } @end 

工作,但原来我有:

 return YES; 

这是在iOS 7上。