Chirag Sondagar
Chirag Sondagar

Reputation: 619

how to single select cell in collection view..?

That are code properly working but when i will scroll my collection view then another cell also selected, for example 18 images are available and first show six at run time when i will select any one of the position then next six position image automatic select. why at a time two cell selecting i am confuse here. please give me solution

enter image description here

here i have take 6 cell at main show storyboard

UICollectionViewFlowLayout *flowLayout = (UICollectionViewFlowLayout*)self.collectionView.collectionViewLayout;

flowLayout.minimumLineSpacing = 15;
CGFloat availableWidthForCells = CGRectGetWidth(self.collectionView.frame) - flowLayout.sectionInset.left - flowLayout.sectionInset.right - flowLayout.minimumInteritemSpacing *2;

cellWidth = availableWidthForCells /6;
    NSLog(@"cellWidth:%f",cellWidth);
flowLayout.itemSize = CGSizeMake(cellWidth, cellWidth);

This is my Didselect And didDeselect Method

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{

    UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];

    cell.layer.cornerRadius = cellWidth / 2.0;
    cell.layer.backgroundColor = [UIColor blackColor].CGColor;
    NSLog(@"INDEXPATH:-%ld",(long)indexPath.row);
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{

    UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
    cell.layer.cornerRadius = cellWidth / 2.0;
    cell.layer.backgroundColor = [UIColor whiteColor].CGColor;

}

Upvotes: 8

Views: 21721

Answers (5)

Nitin
Nitin

Reputation: 93

Swift 5

// This works 100%!!! // In my case, I want to change the background of the button in other words the background of the cell in the collection view: class CustomCVCell: UICollectionViewCell {

override var isSelected: Bool {
    didSet {
        grayBackgroundViewWithImage.image = isSelected ? UIImage(named: "") : UIImage()
    }
}

}

// In the main class where the collection view is stored create this variable: class CustomViewController: UIViewController {

// save the indexPath of last selected cell
private var lastSelectedIndexPath: IndexPath?


// In viewDidLoad() set this value to false:

override func viewDidLoad() {
    super.viewDidLoad()
    customCollectionView.allowsMultipleSelection = false
}

// Further code in data source. In my case, the first cell should be is selected:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCVCell.cellID(), for: indexPath) as! CustomCVCell
    // update first select state from initial.
    if indexPath.row == 0 && lastSelectedIndexPath == nil {
        lastSelectedIndexPath = indexPath
        cell?.isSelected = true
    } else {
        // update last select state from lastSelectedIndexPath
        cell?.isSelected = (lastSelectedIndexPath == indexPath)
    }
    cell.isSelected = (lastSelectedIndexPath == indexPath)
    return cell
}

// Further code in the delegate:
// UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    guard lastSelectedIndexPath != indexPath else { return }
    
    if let index = lastSelectedIndexPath {
        let cell = collectionView.cellForItem(at: index) as! CustomCVCell
        cell.isSelected = false
    }
    let cell = collectionView.cellForItem(at: indexPath) as! CustomCVCell
    cell.isSelected = true
    lastSelectedIndexPath = indexPath
}

}

Upvotes: 0

Alberto Scampini
Alberto Scampini

Reputation: 798

This is happening because the collectionView reuse the cells;

you should store the selected cell's IndexPath in a variable:

ObjC :

@property (nonatomic, retain) NSIndexPath *selectedIndexPath;

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {

    UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];

    cell.layer.backgroundColor = [UIColor blackColor].CGColor;
    NSLog(@"INDEXPATH:-%ld",(long)indexPath.row);

    self.selectedIndexPath = indexPath
}
-(void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{

    UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
    cell.layer.backgroundColor = [UIColor whiteColor].CGColor;

    self.selectedIndexPath = nil
}

Swift :

var selectedIndexPath: IndexPath?

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)

    cell.layer.backgroundColor = UIColor.black

    self.selectedIndexPath = indexPath
}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell = collectionView.cellForItem(at: indexPath)

    cell.layer.backgroundColor = UIColor.white

    self.selectedIndexPath = nil
}

than in "cell for row at indexPath" check :

ObjC :

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];
    cell.layer.cornerRadius = cellWidth / 2.0;
    if (self.selectedIndexPath != nil && indexPath == self.selectedIndexPath) {
        cell.layer.backgroundColor = [UIColor blackColor].CGColor;
    else {
        cell.layer.backgroundColor = [UIColor whiteColor].CGColor;
   }

    return cell
}

Swift :

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

    let cell = collectionView.cellForItem(at: indexPath)
    cell.layer.cornerRadius = cellWidth / 2

    if self.selectedIndexPath != nil && indexPath == self.selectedIndexPath {
        cell.layer.backgroundColor = UIColor.black
    else {
        cell.layer.backgroundColor = UIColor.white
    }
}

Upvotes: 12

William Tong
William Tong

Reputation: 475

I know that I am late to the party. I had the same problem. And after looking around in stackoverflow. Here's my solution. It may help starters understand the UICollectionViewCell a bit easier.

"cellForItemAtIndexPath" method controls how the cell will be display. And cells that are off-screen will not be updated.

Swift 4

First, you need to sub-class your cell.

class SubclassedCell: UICollectionViewCell {

      @IBOutlet var cellImage: UIImageView!
      @IBOutlet var cellCaption: UILabel!

}

extension SubclassedCell{

   func highlightEffect(){
      self.layer.borderWidth = 3.0
      self.layer.borderColor = UIColor.lightGray.cgColor
   }

   func removeHighlight(){
      
      self.layer.borderColor = UIColor.clear.cgColor
   }

} 

And now for the "cellForItemAt" method.

   func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    
    
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "blahblahblah", for: indexPath) as! SubclassedCell
  
    
    cell.cellImage.image = yourImages[indexPath.item]
    cell.cellCaption.text = yourImageNames[indexPath.item]
    cell.removeHighlight()  // Call subclassed cell method.
    if indexPath.item == selectedItem {
        cell.highlightEffect() // Call subclassed cell method.
        preSelected = IndexPath(item: indexPath.item, section: indexPath.section)
        
        
    }
    
    collecttionRef = collectionView
    return cell
    
}

Then, for the "didSelectItemAt" method

  func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath){
    
    collectionView.allowsMultipleSelection = false
    if let cell = collectionView.cellForItem(at: indexPath) as! SubclassedCell?{
        let indexPathData = NSKeyedArchiver.archivedData(withRootObject: indexPath)
        UserDefaults.standard.set(indexPathData,forKey: "backgroundIndexPath")
        //I got some unwrapped crash for my App so I have to use UserDefault to fix the unwrapped problem. You could ignore these both lines.

        selectedItem = indexPath.item //selectedItem is used in the "cellForItemAt" method above.
        
        

        collectionView.reloadData() //update all cells. It could be heavy if you have many cells.
        
    }
   
}

Upvotes: 2

Mostafa Sh
Mostafa Sh

Reputation: 102

Thanks for Alberto Scampini this code for swift 3.1

var selectedIndexPath: IndexPath?

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

    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "SegmentChoiceCVCell", for: indexPath) as! SegmentChoiceCVCell
    //configure cell

    if selectedIndexPath != nil && indexPath == selectedIndexPath {
        cell.checkIcon.backgroundColor = UIColor.black

    }else{

        cell.checkIcon.backgroundColor = UIColor.white
    }

    return cell

}



func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {

    let cell = collectionView.cellForItem(at: indexPath) as! SegmentChoiceCVCell

        cell.checkIcon.backgroundColor = UIColor.black
    self.selectedIndexPath = indexPath

}

func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
    let cell: SegmentChoiceCVCell = collectionView.cellForItem(at: indexPath) as! SegmentChoiceCVCell

        cell.checkIcon.backgroundColor = white
    selectedIndexPath = nil
}

Upvotes: 7

mkhoshpour
mkhoshpour

Reputation: 855

that's because cells are being reused. when you

UICollectionViewCell* cell = [collectionView cellForItemAtIndexPath:indexPath];

and change cell's corner radius, you actually changing more than one cell's corner radius. so you should do this:

let cell = collectionView.dequeueReusableCellWithReuseIdentifier("YourCell", forIndexPath: indexPath) as! YourCell

Upvotes: 0

Related Questions