I am trying to show the selected cell in my UICollectionView
by changing its border and shadow color. my issue is that my DidDeselect
function causes a crash if I select a cell then scroll the selected cell of screen and select another cell, I understand that is because my DidDeselect
is trying to deselect a cell that has been reused so my question is:
How do I remove the border from a cell that is no longer visible once it has scrolled off the screen
My DidSelect
:
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let cell = collectionView.cellForItem(at: indexPath as IndexPath) as! PresentationCell
cell.layer.borderColor = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)
cell.layer.borderWidth = 3
cell.layer.shadowColor = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)
}
My DidDeSelect
:
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
let cellItem = collectionView.cellForItem(at: indexPath) as! PresentationCell
cellItem.layer.borderColor = UIColor.clear.cgColor
cellItem.layer.borderWidth = 3
cellItem.layer.shadowColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
}
It crashes on this line:
let cellItem = collectionView.cellForItem(at: indexPath) as! PresentationCell
Error is : Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Which I understand is because the cell I selected first is no longer displayed because I've scrolled it out of view and then selected a cell at the bottom of the collectionView
How do I get around this?
It is a correct behavior. When you use the dequeueReusableCell
cell are reused and memory gets allocated to visible cells only. So, if you try to pull a cell which is already deallocated then it will gives you nil
.
In your case, you need to have some custom implementation where you can hold the selection and apply the logic.
Following is the working code...
Declare the variable at top
var mySelection = -1
Use this code block for rest of logic
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath)
cell.backgroundColor = .blue
if mySelection == indexPath.row {
applySelection(cell: cell, index: indexPath.row)
} else {
removeSelection(cell: cell, index: indexPath.row)
}
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath)
{
mySelection = indexPath.row
if let cell = collectionView.cellForItem(at: indexPath as IndexPath)
{
applySelection(cell: cell, index: indexPath.row)
}
}
override func collectionView(_ collectionView: UICollectionView,
didDeselectItemAt indexPath: IndexPath)
{
if let cellItem = collectionView.cellForItem(at: indexPath)
{
removeSelection(cell: cellItem, index: indexPath.row)
}
}
func applySelection(cell: UICollectionViewCell, index: Int) {
cell.layer.borderColor = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)
cell.layer.borderWidth = 3
cell.layer.shadowColor = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1)
}
func removeSelection(cell: UICollectionViewCell, index: Int) {
cell.layer.borderColor = UIColor.clear.cgColor
cell.layer.borderWidth = 3
cell.layer.shadowColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1)
}