9

I am implementing a UICollectionView with multiple selection enabled.

Some of my cells are selectable, some are not. Here is the chain of events:

  1. I select a few cells by tapping on them and returning YES to
    • shouldHighlightItemAtIndexPath:
    • shouldSelectItemAtIndexPath:
  2. I try to select a non-selectable cell by tapping on it (the non-selectionable aspect is achieved by returning NO to shouldSelectItemAtIndexPath:)
  3. Result: All selected cells are deselected and didDeselectItemAtIndexPath: is called on them. NOTE: shouldDeselectItemAtIndexPath: is not called.

Expected Result: Nothing happens.

Is this normal behavior? I can't find anything in the docs. If so, how can I go about not deselecting my cells?

Fabien Warniez
  • 2,731
  • 1
  • 21
  • 30
  • Have you set the table view's `allowsMultipleSelection` to YES? – TotoroTotoro Feb 05 '14 at 01:09
  • 1
    I knew I was going to get this question... Should have mentioned it... Yes I did. – Fabien Warniez Feb 05 '14 at 04:57
  • Try implementing the delegate method `tableView:willDeselectRowAtIndexPath:`, set a breakpoint in it, and see when is it called. That might help understand what's happening. – TotoroTotoro Feb 05 '14 at 05:41
  • I am working with UICollectionView, not UITableView. But since these 2 are very similar, I looked into it. There is no `willDoXOrY` methods in the UICollectionViewDelegate protocol but there is a `shouldDeselectItemAtIndexPath` one. I checked, it's not called. Good idea though. – Fabien Warniez Feb 05 '14 at 18:48
  • @BlackRider actually, I did mention on the first line of my post "with multiple selection enabled". – Fabien Warniez Feb 05 '14 at 18:50
  • Possible duplicate of [UICollectionView shouldSelectItemAtIndexPath=NO does not avoid deselecting old selection?](http://stackoverflow.com/questions/14477614/uicollectionview-shouldselectitematindexpath-no-does-not-avoid-deselecting-old-s) – Andrew Hershberger Feb 11 '16 at 20:01
  • Related: http://stackoverflow.com/a/35348930/171089 – Andrew Hershberger Feb 11 '16 at 20:02

2 Answers2

7
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeue...

    cell.userInteractionEnabled = isSelectableIndexPath(indexPath)

    return cell
}

func isSelectableIndexPath(indexPath: NSIndexPath) -> Bool {
    //logic to check if cell is selectable
}

This works by disabling interaction with the cell.

noobular
  • 3,257
  • 2
  • 24
  • 19
6

I had to face exactly the same problem, with collectionView:shouldDeselectItemAtIndexPath: not being called. My solution consist of manually reselect the currently selected cell if I'm tapping on a non-selectable one:

- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    BOOL isSelectable = /* decide if currently tapped cell should be selectable */;

    NSIndexPath *selectedItemIndexPath = /* NSIndexPath of the current selected cell in the collection view, set in collectionView:didSelectItemAtIndexPath: */;

    if (!isSelectable) {
        // the cell isn't selectable, we have to reselect the previously selected cell that has lost selection in the meanwhile
        // without reloading first the cell the selection is not working...
        [collectionView reloadItemsAtIndexPaths:@[selectedItemIndexPath]];
        [collectionView selectItemAtIndexPath:selectedItemIndexPath animated:YES scrollPosition:UICollectionViewScrollPositionNone];
    }

    return isSelectable;
}

If your collection view is scrolling (hiding the currently selected cell) remember to reselect the cell in collectionView:cellForItemAtIndexPath:.

I don't like too much this solution, it's too "hacky", but it works. I would expect to do all the logic in the collectionView:shouldDeselectItemAtIndexPath: but it isn't called and I don't understand why.

chare
  • 71
  • 1
  • 3