【问题标题】:UICollectionViewFlowLayout performance for Text Grid文本网格的 UICollectionViewFlowLayout 性能
【发布时间】: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


【解决方案1】:

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-22
    • 2010-10-16
    • 2018-02-05
    • 1970-01-01
    相关资源
    最近更新 更多