Swift: Uicollectionview Selecting Cell Indexpath Issues

Swift: UICollectionView selecting cell indexPath issues

(NOTE: I updated this for Swift 4 and more modern practices.)

I stick to UIView objects as much as possible.

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) else { return }

performSegue(withIdentifier: "showDetail", sender: cell)
}

Then in prepare(for:sender:)

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier {
case "showDetail":
guard let indexPath = (sender as? UIView)?.findCollectionViewIndexPath() else { return }
guard let detailViewController = segue.destination as? DetailViewController else { return }

detailViewController.selectedImageName = cellImages[indexPath.row]
detailViewController.selectedLabel = cellLabels[indexPath.row]

default: return
}
}

I used an extension I created a while ago findCollectionViewIndexPath()

extension UIView {

func findCollectionView() -> UICollectionView? {
if let collectionView = self as? UICollectionView {
return collectionView
} else {
return superview?.findCollectionView()
}
}

func findCollectionViewCell() -> UICollectionViewCell? {
if let cell = self as? UICollectionViewCell {
return cell
} else {
return superview?.findCollectionViewCell()
}
}

func findCollectionViewIndexPath() -> IndexPath? {
guard let cell = findCollectionViewCell(), let collectionView = cell.findCollectionView() else { return nil }

return collectionView.indexPath(for: cell)
}

}

I have a suspicion that you have a segue in the storyboard already and don't need func collectionView(, didSelectItemAtIndexPath:), but either way, the prepare segue should work.

UICollectionView issue with Select/Deselect cell

As I understand, you want your collectionView can only select 1 cell at a time and if selected cell is clicked again, it will be deselected. If I'm misunderstanding anything, please tell me.

First

  • You shouldn't change textColor of day in didSelectItemAtIndexPath and didDeselectItemAtIndexPath methods. Because when you scroll collectionView, cells will be reused and color of day will be wrong for some cells.
  • To resolve it, using property selected of UICollectionViewCell.

    SmartCalendarDayCell.m

    - (void)setSelected:(BOOL)selected {
    [super setSelected:selected];

    if (selected) {
    self.day.textColor = [UIColor colorWithHexString:@"#D97E66" setAlpha:1];
    } else {
    self.day.textColor = [UIColor lightGrayColor];
    }
    }

Second

  • To deselect selected cell, you should check and do it on collectionView:shouldSelectItemAtIndexPath: method.

    - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    if ([collectionView.indexPathsForSelectedItems containsObject:indexPath]) {
    [collectionView deselectItemAtIndexPath:indexPath animated:NO];
    return NO;
    }

    return YES;
    }

For more detail, you can check my demo repo here.

Why after selecting cell programmatically - cell is not interaction?

You need to call selectItem like this

  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(with: FAFavouriteCategoryCell.self, for: indexPath)!
let currentCategory = categories[indexPath.row]
if selectedCategories.contains(currentCategory.categoryID) {
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .left) //Add this line
cell.isSelected = true
} else {
collectionView.deselectItem(at: indexPath, animated: false)
cell.isSelected = false
}
cell.configCell(category: currentCategory)
return cell
}

UICollectionView selected cells issue

I have also worked on same things, I have following solution for that.

You need to create array of indexPath which will store selected indexPath.

var arrSelectedIndexPath = [IndexPath]()

In cellForRowAtItem method add following code which will check if arrSelectedIndexPath contains indexPath then display selected active background else display inactive background.

if arrSelectedIndexPath.contains(indexPath) {
cell?.backgroundView = collectionActive
} else {
cell?.backgroundView = collectionInactive
}

In didSelect method you need to add following code which also same as above logic, but just add or remove indexPath.

if arrSelectedIndexPath.contains(indexPath) {
cell?.backgroundView = collectionInactive
arrSelectedIndexPath.remove(at: arrSelectedIndexPath.index(of: indexPath)!)
} else {
cell?.backgroundView = collectionInactive
arrSelectedIndexPath.append(indexPath)
}

I hope this solution work for you.

Stored selected indexPath of UICollectionView inside UITableView

This will only work based on the assumption that both your parent table view and child collection views both are not using multiple sections with multiple rows and you only need to store one value for each to represent where an item is located in each respective view.

If I am understanding correctly, you have a collection view for each table view cell. You are storing the selection of each collection view, but you need to also know the position of the collection view in the parent table? A way to do this would be to add a property to your UICollectionView class or use the tag property and set it corresponding section it is positioned in the parent table. Then when you save the selected IndexPath, you can set the section to be that collection view's property you created(or tag in the example) so that each selected indexPath.section represents the table view section, and the indexPath.row represents the collection view's row.

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//...
let collectionView = UICollectionView()
collectionView.tag = indexPath.section
//...
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
indexPath.section = collectionView.tag
let strData = itemFilter[indexPath.section].value[indexPath.item]
//...

}

Basically each selected index path you save will correspond to the following:

indexPath.section = table view section

indexPath.row = collection view row

IndexPath(row: 5, section: 9) would correlate to:

--table view cell at IndexPath(row: 0, section: 9) .

----collection view cell at IndexPath(row: 5, section: 0)

Edit: This is how you can use the saved index paths in your current code

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
//...
let tempIndexPath = IndexPath(row: indexPath.row, section: collectionView.tag)
if arrSelectedIndex.contains(tempIndexPath) {
//...
} else {
//...
}
//...

}

Selecting cell in 1 Collection View to change second Collection View properties (Xcode)

Declare a var:

class ViewController:
var newColor : UIColor?

Change this:

if cell.isSelected {
cell2.iconimage.backgroundColor = cell.backgroundColor
}

for this:

 if cell.isSelected {
newColor = cell.backgroundColor
iconView.reloadData()
}

in

 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

put this

if newColor != nil { // maybe a better test here, if cell was selected
cell2.iconimage.backgroundColor = newColor
}

before

 return cell2



Related Topics



Leave a reply



Submit