55

I have a UICollectionView which is about the size of the screen. The UICollectionViewCells that it displays are the same size as the collectionView. Each cell has a UIImage which is the size of the cell. The CollectionView has paging enabled so essentially it is a full screen photo slideshow that the user can swipe through.

The problem is that
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath is only being called if the user taps with two fingers on a cell or long presses with one finger and then releases. It does not seem to have the default behaviour of single tap selection. I have not made any changes to the CollectionView gesture recognizer so am having trouble finding a solution to this problem.

user3125367
  • 2,920
  • 1
  • 17
  • 17
Kris Gellci
  • 9,539
  • 6
  • 40
  • 47
  • hi Kris I am having the same problem, did you figure out why? – Chris Lin Jun 05 '13 at 09:34
  • I actually had to do a work around where I added my own tap gesture recognizer to each cell. I didn't have this problem in any other collection views in my app, only this particular one. – Kris Gellci Jun 05 '13 at 13:55

15 Answers15

204

Are you sure you're not accidentally overriding - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath? "Select" vs. "deselect" has tripped me up in the past with Xcode's code completion.

Owen Mathews
  • 2,072
  • 1
  • 13
  • 3
  • 2
    I will go ahead and accept your answer not because it fixed my problem but because it fixes a problem very similar to mine. – Kris Gellci Aug 14 '13 at 21:41
  • This is starting to become a ritual for me.. I end up returning to this question every single time I use a `UITableView` or `UICollectionView` o.0 – Rob Sep 29 '15 at 10:46
  • You must also set `collectionView.allowsMultipleSelection = false` (default is false) – Proton Dec 15 '16 at 13:37
134

I was just having the same problem and it turned out that there was a UITapGestureRecognizer on the UIView containing the UICollectionView and it was responding instead.

That explains why didSelectItemAtIndexPath works only if the user taps with two fingers or long presses with one finger because that doesn't trigger the UITapGestureRecognizer.

So, check all the UITapGestureRecognizer you got there, not necessarily on the UICollectionView directly but it could be on any UIView containing it.

iDifferent
  • 2,190
  • 1
  • 14
  • 19
  • 46
    Thanks! Setting `[tapGestureRecognizer setCancelsTouchesInView:NO];` fixed it for me. – Kyle Clegg Oct 01 '13 at 22:11
  • Also check for `self.collectionView.allowsSelection = NO`. If you find this in your code remove the line or set it to YES. Setting to NO will prevent `didSelectItemAtIndexPath` from getting called. – John Erck Feb 03 '16 at 04:10
  • 2
    I had the same issue. I had a UICollectionView that did not respond to didSelectItemAtIndexPath because I had a tapGesture recognizer on the parent view. I set the tapGesture to ```tapGesture?.isEnabled = false``` by default so didSelectItemAtIndexPath would process the tap. Then, in the context of when I needed to use the tapGesture, in my case for detecting a tap away from a UITextField, I simply set my tapGesture to enabled true so my gesture callback would process the tap instead of didSelectItemAtIndexPath. – AgnosticDev Nov 27 '16 at 16:59
  • Saved me! this answer may require some search for the problematic gesture, eventually found the troublemaker and it worked. – Eyzuky Jul 27 '17 at 13:15
  • @iDifferent how to keep the tap gesture recogniser on the rest of the view but let the UICollectionView be selected? – user2363025 Jul 16 '18 at 09:36
  • Helpful answer from IDifferent. Effectively, there was a tap gesture intercepting first tap. I solved it differently: move the view with gesture above the collectionView in objects list in IB, so that it sits behind when running. – claude31 Jan 27 '20 at 11:48
14

If you have a view on the cell which obstructs the cells content view that is intractable then you will not be able to hook into the delegate callback for the cell.

You will want to disable user interaction on the obstructing view either in the NIB or in the code.

view.userInteractionEnabled = NO;

Oliver Atkinson
  • 7,970
  • 32
  • 43
8

Just add to the already resolved question one more situation where the tap gesture might not work, since this did keep tormenting me.

If you return false within UICollectionViewDelegate's collectionView:shouldHighlightItemAtIndexPath:, the tap gesture won't function and the collectionView:didSelectItemAtIndexPath: would not be called. The default return value of this delegate method is true, so you won't have the problem if you don't implement it deliberately.

Blaszard
  • 30,954
  • 51
  • 153
  • 233
  • 1
    This just cost me 3 hours... just by coincidence I had implemented `shouldHighlight` and returned false, to test the delegate connection. (`shouldHighlight` is the first method in the delegate list). Many thanks! – Stan Mar 19 '17 at 00:05
3

I just ran into this problem myself. Originally I had buttons and labels, then I refactored my UI and turned those button/labels into cells for a UICollectionView.

I eventually realized the buttons were consuming my taps. I had unthinkingly just moved my original buttons into the cell, and not turned it into a straight UIImage. I had destroyed the actions associated buttons and was just looking for cell selection so I took me a while to figure it out.

Stupid and obvious in retrospect, but took me a couple hours to realize what I had done.

DBD
  • 23,075
  • 12
  • 60
  • 84
3

If you use only didselect:

self.collectionView.allowsMultipleSelection = false

Or delete that line.

Sour LeangChhean
  • 7,089
  • 6
  • 37
  • 39
2

I just had the same problem...I was overriding touchesBegan in the CollectionCell view and this caused the didSelectItemAtIndexPath to not fire when I touched the cell. Removed the override and all worked.

digthewells
  • 657
  • 5
  • 17
2

In my case it was just

self.collectionView.allowsSelection  =NO;

I had in code.

changing to

self.collectionView.allowsSelection  =YES;

fix it.

user1105951
  • 2,259
  • 2
  • 34
  • 55
2

Try removing all of your UIGestures from the view then test to see if the UICollectionView Cells are able to be interacted with normally.

In my case, I had to remove the lines:

let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
    self.view.addGestureRecognizer(tap)
drfalcoew
  • 615
  • 5
  • 14
1

I ran into this problem in Swift 3 and xcode 8 , I had a view and a collection view inside this.The collection view has userInteractionEnabled to true , still it was not working.Fixed this issue by overriding shouldHighlightItemAt , I dont have any extra / custom implementation in this method , so i did not override this method.After adding the below code the didSelectItem method is called.

func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool {
        return true
    }
1

I'm happened to stumble upon this problem, and it frustrated me one long day until I found this You just need to uncheck "User Interaction Enabled" when I selected the Cell on the top left inside the CollectionView in Storyboard. and problem solved

Phan Hoang
  • 11
  • 1
1

I faced a similar problem and the culprit in my case turned out to be the CardView I was using in UICollectionView Cell's heirarchy. As soon as I disabled the user interaction for the CardView the collectionView started responding to the touch events.

Love Kumar
  • 48
  • 6
0

In case it helps, this just bite me in a silly way spending a couple of hours. Double check if your custom cell is subclassing UICollectionViewCell instead of, let's say, UICollectionReusableView

nandodelauni
  • 291
  • 1
  • 10
0

the top answer works in many cases. but for me, I have a page with complicated gesture, and I met the same situation and the answer does not work for me, finally I got my way:

when adding gestures, set delegate and use this protocal method to deal with it

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch

in this method, you can decide whether the gesture recognizer to receive the touch by your own logic, no matter position or the page's hidden property, based on your demand. once the method return NO, the gesture won't react the touch, in this case the collectionView or tableView can react the selection correctly.

childrenOurFuture
  • 1,889
  • 2
  • 14
  • 23
-1

Remember to add UICollectionViewDataSource, UICollectionViewDelegate to the class

TylerC
  • 95
  • 1
  • 6