【问题标题】:UICollectionView Performance Problems on performBatchUpdatesperformBatchUpdates 上的 UICollectionView 性能问题
【发布时间】:2012-09-15 20:26:33
【问题描述】:

我们正在尝试使用自定义布局设置 UICollectionView。每个 CollectionViewCell 的内容将是一个图像。总体而言,将有数千张图像,并且在某个特定时间可以看到大约 140-150 张图像。在一个动作事件上,所有单元格的位置和大小都可能重新组织。目标是为当前使用 performBatchUpdates 方法的所有移动事件设置动画。这会导致所有内容都被动画化之前的巨大延迟时间。

到目前为止,我们发现内部方法 layoutAttributesForItemAtIndexPath 为每个单元格(总共数千个)调用。此外,调用 cellForItemAtIndexPath 方法的单元格比实际显示在屏幕上的单元格多。

有没有可能提高动画的性能?


默认的 UICollectionViewFlowLayout 并不能真正提供我们想要在应用程序中实现的那种设计。这是我们的一些代码:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
RPDataModel *dm = [RPDataModel sharedInstance]; //Singleton holding some global information
NSArray *plistArray = dm.plistArray; //Array containing the contents of the cells
NSDictionary *dic = plistArray[[indexPath item]];
RPCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"CELL" forIndexPath:indexPath];
cell.label.text = [NSString stringWithFormat:@"%@",dic[@"name"]];
cell.layer.borderColor = nil;
cell.layer.borderWidth = 0.0f;
[cell loadAndSetImageInBackgroundWithLocalFilePath:dic[@"path"]]; //custom method realizing asynchronous loading of the image inside of each cell
return cell;
}

layoutAttributesForElementsInRect 遍历所有元素,为矩形内的所有元素设置 layoutAttributes。 for 语句在第一个单元格超出矩形右下角定义的边界时中断:

-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect {
NSMutableArray* attributes = [NSMutableArray array];
RPDataModel *dm = [RPDataModel sharedInstance];
for (int i = 0; i < dm.cellCount; i++) {
    CGRect cellRect = [self.rp getCell:i]; //self.rp = custom object offering methods to get information about cells; the getCell method returns the rect of a single cell
    if (CGRectIntersectsRect(rect, cellRect)) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:[dm.relevanceArray[i][@"product"] intValue] inSection:0];
        UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
        attribute.size = cellRect.size;
        attribute.center = CGPointMake(cellRect.origin.x + attribute.size.width / 2, cellRect.origin.y + attribute.size.height / 2);
        [attributes addObject:attribute];
    } else if (cellRect.origin.x > rect.origin.x + rect.size.width && cellRect.origin.y > rect.origin.y + rect.size.height) {
        break;
    }
}
return attributes;
}

在布局更改时,无论在 layoutAttributesForElementsInRect 中定义的单元格数量是否有限,结果都几乎相同。如果不受限制,系统要么获取其中所有单元格的布局属性,要么如果它是有限的,它会为所有缺失的单元格调用 layoutAttributesForElementAtIndexPath 方法。总体而言,每个单元格的属性都在以某种方式使用。

-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
RPDataModel *dm = [RPDataModel sharedInstance];
UICollectionViewLayoutAttributes *attribute = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
CGRect cellRect = [self.rp getCell:[dm.indexDictionary[@(indexPath.item)] intValue]];
attribute.size = cellRect.size;
attribute.center = CGPointMake(cellRect.origin.x + attribute.size.width / 2, cellRect.origin.y + attribute.size.height / 2);
return attribute;
}    

【问题讨论】:

  • 请从您的 UICollectionViewLayout 发布您的代码。

标签: ios performance ios6 uicollectionview


【解决方案1】:

没有看到代码,我的猜测是您的 layoutAttributesForElementsInRect 方法正在遍历集合中的所有项目,这反过来又导致其他方法被过度调用。 layoutAttributesForElementsInRect 给你一个提示 - 即它传递给你的 CGRect - 关于你需要为哪些项目调用 layoutAttributesForItemAtIndexPath ,就屏幕上的内容而言。

所以这可能是性能问题的一部分 - 即调整您的自定义布局,以便它能够智能地了解正在更新的项目。

其他问题通常与动画性能有关。需要注意的一件事是是否正在进行任何类型的合成 - 确保您的图像是不透明的。另一件事是,如果您在图像上使用阴影,那么制作动画可能会很昂贵。提高阴影动画性能的一种方法是在调整图像大小时设置 shadowPath 值 - 如果您确实有阴影,请告诉我并发布一些代码。

【讨论】:

  • 我们已经遍历了给定 layoutAttributesForElementsInRect 的矩形内的所有元素。系统仍然为矩形外的所有单元格调用 layoutAttributesForItemAtIndexPath 方法。对于图像,我们根本不使用任何阴影,它们已经是不透明的。一个问题可能是一次可见的视图数量(大约 140)。
  • 如果您发布代码会很有帮助。一个建议,出于调试目的,使用内置的 UICollectionViewFlowLayout 实现相同的集合视图,并为其提供与您在自定义视图中使用的参数相似的参数。触发导致 UICollectionViewFlowLayout 以显着方式重组的事件,并查看动画是否更好。
  • 仅供参考,Apple 终于发布了 CollectionViews 的示例代码项目。不幸的是,这是一个极其简单的实现——没有自定义布局,这是我真正需要看到的代码。
【解决方案2】:

这似乎是由于尝试将单元格添加到具有标题视图但其中没有单元格的部分。

该错误消息非常无用,并且需要花费几个小时的努力才能找到它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-06
    • 2017-02-03
    • 1970-01-01
    • 2012-09-21
    • 1970-01-01
    • 2016-03-09
    • 2023-03-21
    • 1970-01-01
    相关资源
    最近更新 更多