【发布时间】:2014-09-05 13:07:48
【问题描述】:
我有一个使用 Storyboard 的 iOS 7 应用,其结构如下:
UITabBarController->UINavgiationController->UICollectionViewController
我使用 UICollectionViewFlowLayout 的自定义子类来布局网格。每个单元格包含一个 UILabel。
我正在尝试在 UICVC 中呈现 5 列网格。可以有超过 800 行(部分,每个部分一行)。我大致基于 Erica Sadun 在她的 iOS 书中的示例代码。
所有单元格都有特定的固定宽度(使用了 2 种不同的宽度)。所有单元格具有相同的高度。网格比物理显示更宽,因此可以水平和垂直滚动。
一切正常,但是超过 30 行的性能一直很差。尝试计算自定义布局时出现问题,特别是在以下方法中:
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
NSArray *attribs = [super layoutAttributesForElementsInRect:rect];
NSMutableArray *attributes = [NSMutableArray array];
[attribs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *currentLayout, NSUInteger idx, BOOL *stop)
{
NSString *layoutItemKey = [NSString stringWithFormat:@"%ld:%ld", (long)currentLayout.indexPath.section, (long)currentLayout.indexPath.item];
UICollectionViewLayoutAttributes *newLayout = [self.cachedLayoutAttributes objectForKey:layoutItemKey];
if (nil == newLayout)
{
newLayout = [self layoutAttributesForItemAtIndexPath:currentLayout.indexPath];
long section = currentLayout.indexPath.section;
long item = currentLayout.indexPath.item;
NSString *layoutItemKey = [NSString stringWithFormat:@"%ld:%ld", (long)section, (long)item];
[self.cachedLayoutAttributes setObject:newLayout forKey:layoutItemKey];
}
[attributes addObject:newLayout];
}];
return attributes;
}
这里的主要延迟似乎来自对 iOS 方法的调用:
layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;
在 layoutAttributesForItemAtIndexPath 方法中:
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewLayoutAttributes *attributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGSize thisItemSize = [self sizeForItemAtIndexPath:indexPath];
CGFloat verticalOffset = [self verticalInsetForItemAtIndexPath:indexPath];
CGFloat horizontalOffset = [self horizontalInsetForItemAtIndexPath:indexPath];
if (self.scrollDirection == UICollectionViewScrollDirectionVertical)
attributes.frame = CGRectMake(horizontalOffset, verticalOffset, thisItemSize.width, thisItemSize.height);
else
attributes.frame = CGRectMake(verticalOffset, horizontalOffset, thisItemSize.width, thisItemSize.height);
return attributes;
}
滚动工作正常到一个点,然后在计算下一个布局块时冻结大约 1.5 秒(似乎总是大约 165 个单元格)。由于我正在缓存所有内容,因此下次用户滚动时性能很好。
如果我将单元格宽度留给 UICollectionViewFlowLayout 默认值,一切都会顺利进行,没有停顿。
为了加快速度,我有:
- 确保所有视图都是不透明的
- 将 CollectionView 的减速率设置为 FAST
- Made - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 返回 NO
- 我缓存了所有计算的 UICollectionViewLayoutAttributes
- 我在初始化时缓存了前 50 行。这样做没有明显的延迟,并且它使初始滚动性能比原本要好一些
我想尽办法从 UICollectionViewFlowLayout 中获得更多性能。
谁能建议我如何改进代码?
谢谢
达伦。
【问题讨论】:
-
当你计算layoutAttributesForElementsInRect中的属性时,你是只为传入的rect计算它们还是为所有单元格计算它们?屏幕上同时显示多少个单元格?
-
感谢您的回复。我已经编辑了原始问题以添加该方法的代码。我在开始时调用 super 来获取矩形中元素的布局属性,这发生得非常快(使用默认的 UICollectionViewFlowLayout 非常快)。然后我逐步浏览它们并重新计算新的布局。据我所知,只有在尝试计算新的布局属性时才会出现延迟。
-
等 newLayout = [self layoutAttributesForItemAtIndexPath:currentLayout.indexPath];线?你也重写了那个方法吗?
-
我有,虽然主要使用 Erica Sadun 的示例代码。我已经更新了要添加到代码中的问题。仅供参考,layoutAttributesForCellWithIndexPath:(NSIndexPath *)indexPath;未被覆盖。
标签: ios objective-c uicollectionview uicollectionviewlayout