Возможно ли обменять 2 ячейки в UICollectionView, использующем UICollectionViewFlowLayout?

Скажем, у меня есть UICollectionView, используя UICollectionViewFlowLayout и следующий формат:

1 2 3
4 5 6
7 8 9

Я касаюсь ячейки 9 и перетаскиваю ее по ячейке 6, перемещая ячейку 9 туда, где находится ячейка 6, и ячейка 6, где ячейка 9:

1 2 3
4 5 9
7 8 6

Есть ли способ легко перемещать и анимировать ячейку 6, где находится ячейка 9, а также перемещать и анимировать ячейку 9, где находится ячейка 6? Или мне нужно подклассы UICollectionViewLayout? Если мне нужно подклассифицировать UICollectionViewLayout, как это сделать? Я попытался явно установить центры ячеек в

-(UICollectionViewLayoutAttributes*)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath

но без успеха.

Ответ 1

После большого удара головой, решение, которое я нашел, заключается в использовании moveItemAtIndexPath:toIndexPath внутри performBatchUpdates:completion. Согласно documentation для performBatchUpdates:completion:

Вы можете использовать этот метод в тех случаях, когда вы хотите вставлять, удалять, перезагружать или перемещать ячейки вокруг представления коллекции в одной анимационной операции, в отличие от нескольких отдельных анимаций. Используйте заблокированный, переданный в параметре обновлений, чтобы указать все операции, которые вы хотите выполнить.

Итак, что я в основном делал, было

[self performBatchUpdates:^{
    [self moveItemAtIndexPath:fromIp toIndexPath:toIp];
    [self moveItemAtIndexPath:toIp toIndexPath:fromIp];
} completion:^(BOOL finished) {
    // update data source here
    // e.g [dataSource exchangeObjectAtIndex:fromIp.row withObjectAtIndex:toIp.row];
}];

Ответ 2

Вы пытались переупорядочить элементы напрямую с помощью moveItemAtIndexPath: toIndexPath:?

- убедитесь, что вы действительно переупорядочиваете базовую коллекцию моделей, чтобы изменения вступили в силу после полной перезагрузки в следующий раз.

Ответ 3

Быстрый код:

        self.collectionView.performBatchUpdates({
            self.collectionView.moveItem(at: selectedIndexPath, to: targetIndexPath)
            self.collectionView.moveItem(at: targetIndexPath, to: selectedIndexPath)
        }, completion: nil)