InitialLayoutAttributesForAppearingItemAtIndexPath запускается для всех видимых ячеек, а не только вставленных ячеек
Кто-нибудь видел достойный ответ на эту проблему?
initialLayoutAttributesForAppearingItemAtIndexPath
, кажется, вызывается для всех видимых ячеек, а не только для вставленной ячейки. Согласно собственные документы Apple:
Для перемещенных элементов в представлении коллекции используются стандартные методы для извлечения обновленных атрибутов макета. Для вставленных или удаленных элементов представление коллекции вызывает несколько разных методов, которые вы должны переопределить, чтобы предоставить соответствующую информацию о макете
Что не похоже на то, что происходит... другие ячейки не вставлены, они перемещаются, но он вызывает initialLayoutAttributesForAppearingItemAtIndexPath
для тех, кто перемещается тоже.
Я видел работу вокруг, используя prepareForCollectionViewUpdates:
, чтобы отслеживать, какие indexPaths обновляются и только меняют их, но это кажется немного странным, что он снова возвращается к своим собственным документам. Кто-нибудь еще нашел лучший способ обойти это?
Ответы
Ответ 1
Я нашел это сообщение в блоге Mark Pospesel, чтобы быть полезным.
Автор также установил образец WWDC CircleLayout
и разместил его на Github.
Предложенные методы:
- (void)prepareForCollectionViewUpdates:(NSArray *)updateItems
{
// Keep track of insert and delete index paths
[super prepareForCollectionViewUpdates:updateItems];
self.deleteIndexPaths = [NSMutableArray array];
self.insertIndexPaths = [NSMutableArray array];
for (UICollectionViewUpdateItem *update in updateItems)
{
if (update.updateAction == UICollectionUpdateActionDelete)
{
[self.deleteIndexPaths addObject:update.indexPathBeforeUpdate];
}
else if (update.updateAction == UICollectionUpdateActionInsert)
{
[self.insertIndexPaths addObject:update.indexPathAfterUpdate];
}
}
}
- (void)finalizeCollectionViewUpdates
{
[super finalizeCollectionViewUpdates];
// release the insert and delete index paths
self.deleteIndexPaths = nil;
self.insertIndexPaths = nil;
}
// Note: name of method changed
// Also this gets called for all visible cells (not just the inserted ones) and
// even gets called when deleting cells!
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
// Must call super
UICollectionViewLayoutAttributes *attributes = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];
if ([self.insertIndexPaths containsObject:itemIndexPath])
{
// only change attributes on inserted cells
if (!attributes)
attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
// Configure attributes ...
attributes.alpha = 0.0;
attributes.center = CGPointMake(_center.x, _center.y);
}
return attributes;
}
// Note: name of method changed
// Also this gets called for all visible cells (not just the deleted ones) and
// even gets called when inserting cells!
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
{
// So far, calling super hasn't been strictly necessary here, but leaving it in
// for good measure
UICollectionViewLayoutAttributes *attributes = [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath];
if ([self.deleteIndexPaths containsObject:itemIndexPath])
{
// only change attributes on deleted cells
if (!attributes)
attributes = [self layoutAttributesForItemAtIndexPath:itemIndexPath];
// Configure attributes ...
attributes.alpha = 0.0;
attributes.center = CGPointMake(_center.x, _center.y);
attributes.transform3D = CATransform3DMakeScale(0.1, 0.1, 1.0);
}
return attributes;
}
Ответ 2
Ты не один. Комментарии к заголовку UICollectionViewLayout делают вещи немного яснее.
Для каждого элемента на экране перед недействительностью, finalLayoutAttributesForDisappearingXXX будет вызван и настройки анимации из того, что находится на экране, до тех последних атрибутов.
Для каждого элемента на экране после недействительности, initialLayoutAttributesForAppearingXXX будет называться анимацией настройте из этих исходных атрибутов на то, что заканчивается на экране.
В основном finalLayoutAttributesForDisappearingItemAtIndexPath
вызывается для каждого элемента на экране перед запуском блока анимации, и initialLayoutAttributesForAppearingItemAtIndexPath
вызывается для каждого элемента после завершения блока анимации. Вам нужно кэшировать массив объектов UICollectionViewUpdateItem, отправленных в prepareForCollectionViewUpdates
, чтобы вы знали, как настроить начальные и конечные атрибуты. В моем случае я кэшировал предыдущие прямоугольники макета в prepareLayout
, поэтому я знал правильные исходные позиции для использования.
Одна вещь, которая застопорилась мне некоторое время, - вы должны использовать супер-реализацию initialLayoutAttributesForAppearingItemAtIndexPath
и изменить возвращаемые атрибуты. Я просто вызывал layoutAttributesForItemAtIndexPath
в моей реализации, а анимация не работала, потому что позиции макета были разными.
Ответ 3
Если вы подклассифицировали UICollectionViewFlowLayout
, вы можете вызвать реализацию super
. После того, как вы получили начальный макет по умолчанию, вы можете проверить .alpha
0
. Если alpha
- это нечто иное, чем 0
, ячейка перемещается, если она 0
вставляется.
Немного взлома, я знаю, но он работает.
Ниже приведена версия Swift 2.0:
override func initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
guard let attributes = super.initialLayoutAttributesForAppearingItemAtIndexPath(itemIndexPath) where attributes.alpha == 0 else {
return nil
}
// modify attributes for insertion here
return attributes
}
Ответ 4
Убедитесь, что вы используете новую сигнатуру метода в Swift 3. Автокоррекция не работает для этого метода:
func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes?