I have both tableViews and collectionViews in my project app. In both tables and collections, I want a row/cell to be selected when first tapped, and deselected when tapped second time.
With the tableView, I found a fairly straightforward and simple solution here, which works great.
CollectionView, on the other hand, turned out to be a whole different type of beast. Unlike tableView, there is no willSelectItemAt
delegate method, so there is no way to check if item was in selected state before the second tap is registered. Implementing shouldDeselectItemAt
and didDeselectItemAt
gives no result - these methods never get called on a cell that's already selected when tapped.
The only plausible solution suggests creating a UIButton
for each collectionView cell, but should it really be that complicated?
Try using the "shouldSelectItem" UIColllectionViewDelegate method.
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
let item = collectionView.cellForItem(at: indexPath)
if item?.isSelected ?? false {
collectionView.deselectItem(at: indexPath, animated: true)
} else {
collectionView.selectItem(at: indexPath, animated: true, scrollPosition: [])
return true
}
return false
}
A shorter version of @pkorosec answer, with exact the same effect, is the following:
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
if collectionView.cellForItem(at: indexPath)?.isSelected ?? false {
collectionView.deselectItem(at: indexPath, animated: true)
return false
}
return true
}
An alternative, suggested by @Manav, is:
override func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
if collectionView.indexPathsForSelectedItems?.contains(indexPath) ?? false {
collectionView.deselectItem(at: indexPath, animated: true)
return false
}
return true
}
Another option, that I personally think is way cleaner, is to allow multiple selection on collection view and then manually deselect the currently selected item before next selection.
First step: allow multiple selection
override func viewDidLoad() {
super.viewDidLoad()
collectionView.allowsMultipleSelection = true
}
Second step: manually deselect previously selected item
func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
collectionView.indexPathsForSelectedItems?.forEach { ip in
collectionView.deselectItem(at: ip, animated: true)
}
return true
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With