2

How can I deselect a NSCollectionViewItem by clicking on it again?

This is the code I use for selecting and deselecting:

func collectionView(collectionView: NSCollectionView, didSelectItemsAtIndexPaths indexPaths: Set<NSIndexPath>) {
        print("selected")
        guard let indexPath = indexPaths.first else {return}
        print("selected 2")
        guard let item = collectionView.itemAtIndexPath(indexPath) else {return}
        print("selected 3")
        (item as! CollectionViewItem).setHighlight(true)
    }

    func collectionView(collectionView: NSCollectionView, didDeselectItemsAtIndexPaths indexPaths: Set<NSIndexPath>) {
        print("deselect")
        guard let indexPath = indexPaths.first else {return}
        print("deselect 2")
        guard let item = collectionView.itemAtIndexPath(indexPath) else {return}
        print("deselect 3")
        (item as! CollectionViewItem).setHighlight(false)
    }

/////////////////////

    class CollectionViewItem: NSCollectionViewItem {


        func setHighlight(selected: Bool) {

            print("high")
            view.layer?.borderWidth = selected ? 5.0 : 0.0
            view.layer?.backgroundColor = selected ? NSColor.redColor().CGColor : NSColor(calibratedRed: 204.0/255, green: 207.0/255, blue: 1, alpha: 1).CGColor
        }
    }

This code deslect when another item is clicked, but not when the same item is. I want to deselct when the same item is clicked.

sanjihan
  • 5,592
  • 11
  • 54
  • 119

3 Answers3

5

You can achieve this by observing the selected state on the item, and installing an NSClickGestureRecognizer on the item's view when it's selected, and uninstalling it when it is deselected.

Put the following code somewhere in your NSCollectionViewItem subclass:

- (void)onClick:(NSGestureRecognizer *)sender {
    if (self.selected) {
        //here you can deselect this specific item, this just deselects all
        [self.collectionView deselectAll:nil];
    }
}

- (void)setSelected:(BOOL)selected {
    [super setSelected:selected];
    if (selected) {
        [self installGestureRecognizer];
    }
    else {
        [self uninstallGestureRecognizer];
    }
}

- (void)installGestureRecognizer {
    [self uninstallGestureRecognizer];

    self.clickGestureRecognizer = [[NSClickGestureRecognizer alloc] initWithTarget:self
                                                                            action:@selector(onClick:)];
    [self.view addGestureRecognizer:self.clickGestureRecognizer];
}

- (void)uninstallGestureRecognizer {
    [self.view removeGestureRecognizer:self.clickGestureRecognizer];
    self.clickGestureRecognizer = nil;
}
Marko Hlebar
  • 1,973
  • 17
  • 18
0

One easy trick is to use CMD - Left mouse click. Although this doesn't solve my problem exactly, it is still better than nothing.

sanjihan
  • 5,592
  • 11
  • 54
  • 119
0

Thank Marko Hlebar for his answer.

Based on this, I realized the function of clicking the item to switch its selection.

class MyItem: NSCollectionViewItem {
    override var isSelected: Bool {
        didSet {
            self.view.layer?.backgroundColor = (isSelected ? NSColor.blue : NSColor.gray).cgColor
            // If the selection causes the size to change, re-layout.
            self.collectionView?.collectionViewLayout?.invalidateLayout()
        }
    }

    override func viewDidLoad() {
        self.view.wantsLayer = true
        self.view.addGestureRecognizer(NSClickGestureRecognizer(target: self, action: #selector(onClick(sender:))))
    }

    @objc private func onClick(sender: NSGestureRecognizer) {
        guard let indexPath = self.collectionView?.indexPath(for: self) else { return }
        if self.isSelected {
            self.collectionView?.deselectItems(at: [indexPath])
        } else {
            self.collectionView?.selectItems(at: [indexPath], scrollPosition: [])
        }
    }
}
jqgsninimo
  • 6,562
  • 1
  • 36
  • 30