Мы пытаемся настроить 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;
}