Using a UIPanGestureRecognizer to Delete Cells in a UICollectionView Swift 3

Luigi M
5 min readFeb 20, 2017

--

I wanted to share a quick little project that uses a UIPanGestureRecognizer to delete cells in a UICollectionView. Here is a sample of what it looks like:

This assumes you have a basic knowledge of how to create a UICollectionView and a custom CollectionViewCell. The project files can be located here:

The project is quite simple when it comes to the UI. All I did was create a UICollectionViewController with a custom cell that I embedded in a navigation controller.

Setting Up The CollectionView:

Very quickly lets go through the basic setup of the UICollectionView

Because we are using a UICollectionViewController we don’t need to set the delegate as Xcode does this for us. We do however set the UICollectionViewDelegateFlowLayout to allow us to adjust the cell frame which we do in the first function after viewDidLoad().

The next three functions are the standard collectionView functions where we set the number of sections, the numberOfItemsInSection which we set to the grocerList.count, and then creating the cell itself.

You might be wondering where the function is that allows me to delete the cells…don’t worry I’m going to get to it a little later.

Setting Up the Custom Cell:

Here is where most of our code is going to live. Lets start by going over our variables and initializers.

I’ve created a few variables here. The cellLabel which is going to store our grocery item, two deleteButton labels which will be added below our content view on the left or the right depending on which way we pan. And of course our pan gesture recognizer. We also added the UIGestureRecognizerDelegate protocol to our class. I’ll explain why later on.

Next we have our two init methods where I call a custom function I created called comonInit().

I am still a bit hazy when it comes to the required init, but from my understanding we need to use this when we create our own custom class init . This required init allows us to “unarchive” the data via an NSCoder.

It seems like there is a lot going on in here, but it’s really quite simple. Instead of creating these objects in storyboard we are doing so manually so we have to initialize each object and add it to our view. Let’s go through it one item at a time.

First off I am setting the contentView’s background color to gray and self.background color to red. Each cell has a contentView which displays objects or colors we want in the cell. When I set self.background color I am actually setting the color beneath the contentView.

After I do this I initialize the cellLabel and add it to the contentView. I am also setting translatesAutoresizingMaskIntoConstraints to false which allows me to manually set the constraints of that label. If I didn’t do this autolayout tries to create the constraints for me.

Similarly I initialize the deleteLables and insert them BELOW the contentView. Because I want these labels to movie with my pan I don’t set the frames here. Instead I set the frames when the pan is happening..you will see were shortly.

Lastly I initialize the pan gesture with an action called onPan. Much like you would when you create a UIButton. I also set the delegate to self..self being the CustomCell class.

Now that our view is initialized lets work on our pan gesture:

Making the Pan Gesture:

First let’s look at our onPan function. You’ll notice we have and if statement that covers some of the different states of our gesture. If the state is ‘began’ we do nothing, if the state is ‘changed’ we call setNeedsLayout(). This method says “on the next run loop call layoutSubViews().” When someone presses our cell the state changes to began and then when they move the cell to the left or right the state turns to changed and layoutSubViews() is called.

Now in layoutSubViews() we check to see if the state is changed and if it is we get the current point of the pan by calling translation(in: View) which returns “A point identifying the new location of a view in the coordinate system of its designated superview.” We then set the frames of the contentView and the deleteLabels based on that point.

Now going back to our onPan function we have an else statement that checks our pan gestures velocity to see if it’s greater than 500 points per second. You’ll notice abs prior to checking the velocity. This get’s the absolute value and the reason we do this is because the user can pan right or left so the value could be negative. If that condition is met we now create a constant for our collectionView and get the indexPath by using the CGPoint of where we are pressing on the collectionView. Once we have this we can then tell the collectionView to call on the below function, which we haven’t yet implemented in our CollectionViewController class so let’s go back and do that.

As you can see when we call this function we are deleting the item at that indexPath from both collectionView and our groceryList.

Now if you run the app here you will be able to delete the cells just fine, but you’ll notice that when you press a cell and try to scroll down you won’t be able to do so. This is where adding UIGestureRecognizerDelegate protocol to our CustomCell comes into play. We want to add two functions to our CustomCell.

The first one simply allows our cell to be able to handle multiple gesture recognizers. So now our pan gesture and our scroll gesture can work together.

The next function is allowing us to dictate when our gesture should begin. We set this to be true if the velocity in our x direction is greater than the velocity in our y direction, because we only want our pan to work in the left and right direction when the user wants to delete something. If the velocity is greater in the y direction we assume the user is trying to scroll.

And that’s it!

--

--