Vin Gazoil
Vin Gazoil

Reputation: 2020

Move hidden UICollectionViewCell seamlessly with a custom UICollectionViewLayout

I implemented a custom mechanism to perform reordering using drag and drop in a UICollectionView, using a UILongPressGestureRecognizer.

I have a very simple UICollectionView with a custom UICollectionViewLayout.
My layout class is not a subclass of UICollectionViewFlowLayout.

Here is how it looks like:

layout

When I start lifting a cell to begin the drag, I update a dropProposalIndexPath property in my custom layout object so it knows which cell needs to be hidden.

My custom UICollectionViewLayout subclass returns a UICollectionViewLayoutAttributes with the alpha property set to 0 for the cell which corresponds to dropProposalIndexPath like so:

if self.dropProposalIndexPath == indexPath {
    itemLayoutAttributes.alpha = 0
}

It makes the lifted cell hidden thus creating a "hole" in the UICollectionView.

When the user moves its finger, I update the dropProposalIndexPath property of my custom UICollectionViewLayout subclass and invalidate its layout, then move the cell that acts as a hole at the new indexPath:

// Inform layout of the indexPath of the dropProposal
self.reorderableLayout?.dropProposalIndexPath = dropProposalIndexPath
// Move the cell 
collectionView.moveItem(at: draggingIndexPath, to: dropProposalIndexPath)

Here is how it looks:

video demonstrating cell blinking when moving

Pretty bad huh?

I implemented the exact same logic in a demo project using a subclass of UICollectionViewFlowLayout and the transition is seamless:

enter image description here

I guess I'm doing something wrong or forget to do something in my UICollectionViewLayout subclass.

I can post more code if needed.


Please note that using the built-in drag & drop mechanism (introduced with iOS 11) to perform the reordering is not an option, I want to use my custom implementation for various reasons.

Upvotes: 2

Views: 379

Answers (1)

Vin Gazoil
Vin Gazoil

Reputation: 2020

In case someone encounters the same issue, the solution was to implement the following method in your UICollectionViewLayout subclass:

func initialLayoutAttributesForAppearingItem(at: IndexPath) -> UICollectionViewLayoutAttributes?

You then return a UICollectionViewLayoutAttributes with the alpha property set to 0 in the initialLayoutAttributesForAppearingItem function if the itemIndexPath parameter matches the indexPath of your dragging cell.

Upvotes: 3

Related Questions