文本网格的UICollectionViewFlowLayout性能

时间:2014-09-05 13:07:49

标签: ios objective-c uicollectionview uicollectionviewlayout

我有一个使用Storyboard的iOS 7应用程序,它具有以下结构:

UITabBarController-> UINavgiationController-> UICollectionViewController

我使用UICollectionViewFlowLayout的自定义子类来布局网格。每个单元格包含一个UILabel。

我正在尝试在UICVC中渲染一个5列网格。最多可以有800行(部分,每个部分一行)。我已经根据她的iOS书中的Erica Sadun的示例代码进行了松散的基础。

细胞都具有特定的设定宽度(使用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中挤出更多性能的想法。

有人可以建议我如何改进代码吗?

由于

达伦。

1 个答案:

答案 0 :(得分:0)

我找到了问题的解决方案,虽然它不是UICollectionView性能问题的完整答案,但它满足了我的需求。

我正在渲染文字网格。行的高度都相同,字段的宽度始终相同,行的总宽度始终相同。

Erica Sadun的代码允许使用可变高度的文本单元格,我认为是文本包装。因此,需要为每个单元格和行计算布局。对于超过100个单元格的网格,所需的时间太长(在我的iPhone 4S上)。

我所做的是删除所有高度和宽度计算代码,并将其替换为我手动计算的固定值。

这消除了瓶颈,现在我可以渲染一个有几千个单元格的网格而没有任何明显的滞后。