Iphone 滚动时,大UICollectionViewCell停止显示
这里描述的Iphone 滚动时,大UICollectionViewCell停止显示,iphone,ios,uicollectionview,Iphone,Ios,Uicollectionview,这里描述的UICollectionView的相同行为已经导致。尽管我决定发表我自己的一篇文章,因为我做了进一步的调查,但我不想发表评论或编辑上面提到的问题 发生了什么事?: 当使用UICollectionViewFlowLayout在UICollectionView中显示大单元格时,将集合视图滚动到某个偏移量后,这些单元格将消失 当进一步滚动直到另一个单元格进入可见区域时,消失/隐藏的单元格将再次可见 我使用垂直滚动集合视图和全宽单元格进行了测试,但我相当肯定,水平滚动的类似设置也会出现这种情况
UICollectionView
的相同行为已经导致。尽管我决定发表我自己的一篇文章,因为我做了进一步的调查,但我不想发表评论或编辑上面提到的问题
发生了什么事?:
当使用UICollectionViewFlowLayout
在UICollectionView
中显示大单元格时,将集合视图滚动到某个偏移量后,这些单元格将消失
当进一步滚动直到另一个单元格进入可见区域时,消失/隐藏的单元格将再次可见
我使用垂直滚动集合视图和全宽单元格进行了测试,但我相当肯定,水平滚动的类似设置也会出现这种情况
什么是大单元格?:
所述行为发生在单元格高度超过显示高度两倍的情况下(3.5英寸显示器上为960.f+1.f
,4英寸显示器上为1136.f+1.f
)
到底发生了什么?:
当集合视图的滚动偏移量超过cell.frame.origin.y+displayHeightOfHardware
时,cells hidden属性设置为YES
,并调用-collectionView:DiEndDisplayingCell:forItemAtIndexPath:
(例如,在3.5英寸iPhone上,当scrollingOffset.y
达到481.f
时,第一个单元格变为隐藏)
如上所述,当滚动到下一个单元格出现时,隐藏的单元格将再次显示(即隐藏属性更改为否
),而且,当滚动到足够远时,无论滚动到何处,单元格都不会再次消失
当使用大于三倍显示高度(1441.f/1705.f
)的单元格时,这种情况会发生变化。这些单元格显示相同的行为,但无论上下滚动多远,它们都保持不变
还有什么?:
通过覆盖-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
返回YES
无法修复这种情况
在单元格被隐藏后,如果以编程方式将hidden属性设置为NO
,则无法强制显示这些单元格(例如,在DiEndDisplayingCell
中)
那么,问题是什么?:
我很确定,这是
UICollectionView/Controller/Cell/Layout中的一个bug,我将在苹果公司提交一份TSI。但在此期间:有人有什么想法可以快速破解这个问题吗?我有一个非常肮脏的内部解决方案:
@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应用程序规则横加修改
关键是观察到大单元格边界是问题所在。我通过确保单元格的一个边缘位于可滚动内容区域的可视区域内来解决这一问题。显然,您需要根据需要对UICollectionViewFlowLayout类或UICollectionViewLayout类进行子类化,并利用其内容fset值以跟踪您在UIScrollView中的位置
我还必须确保:
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds
返回YES或面临运行时异常,表明布局无效。在本例中,我将较大单元格的边缘绑定到左边缘。这样可以避免对这些较大单元格进行错误的边界相交检测
这确实会创建更多的工作,这取决于您希望单元格内容在滚动时随着单元格宽度/高度的更新而呈现的方式。在我的情况下,单元格中的子视图相对简单,不需要太多的处理
根据要求,这里是我的layouttributesinrect
- (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;
}
-(NSArray*)布局属性ForElementsInRect:(CGRect)rect
{
NSMutableArray*属性=[NSMutableArray];
NSArray*vertical=myVerticalCellsStore.cells;
NSInteger startRow=地板(垂直原点.y*(垂直点计数)/(垂直点计数*垂直点视图Wheight+垂直点视图速度*2));
startRow=(startRow<0)?0:startRow;
对于(NSInteger i=startRow;i=i*verticalViewHeight);i++){
NSArray*horizontals=myHorizontalStore.horizontalCells;
UICollectionViewLayoutAttributes*verticalAttr=[self-LayoutAttributes for Supplmentary View of Kind:@“vertical”atIndexPath:[nsIndepath indexPathForItem:0第1节:i]];
if(CGRectIntersectsRect(垂直坐标系,rect)){
[属性addObject:verticalAttr];
}
BOOL foundAnElement=否;
对于(NSInteger j=0;j
这是我的净化代码。基本上,我计算的第一个单元格应该基于单元格高度。在我的情况下,这是固定的,因此计算非常简单。但是我的水平元素有不同的宽度。因此,内部循环实际上是计算出要包含在属性数组中的正确水平单元格数量。T在这里,我使用CGRectIntersectsRect来确定单元格是否相交。然后循环继续运行,直到相交失败。如果至少找到一个水平单元格,循环将中断。希望这能有所帮助。我的解决方案与Jonathan的基本相同,但属于一个类别,因此您不必使用自己的subc姑娘
@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
@implementat
@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;