ragnarok ragnarok - 17 days ago 8
iOS Question

Reusing cells UICollectionView - some cells don't get selected

In the

UICollectionView
, I've got a custom
UICollectionViewCellClass
, where prepareForReuse is overridden for default formatting staff.

I've got an
NSMutableArray
containing
NSIndexPaths
from didSelectItemAtIndexPath:.

In cellForItemAtIndexPath: I reformat the selected cells so they appear selected.

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

ButtonCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ButtonCell" forIndexPath:indexPath];

NSString *title = self.ingredientsBook.names[indexPath.item];

cell.label.text = title;

if ([self isSelectedIndexPath:indexPath]){

cell.backgroundColor = [UIColor whiteColor];
cell.label.textColor = [UIColor blueColor];
}
return cell;

}

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

self.searchButton.enabled = YES;

ButtonCell *cell = (ButtonCell *)[collectionView cellForItemAtIndexPath:indexPath];
[selectedCellIndexPaths addObject:indexPath];
NSLog(@"%@", selectedCellIndexPaths);
cell.backgroundColor = [UIColor whiteColor];
cell.label.textColor = [UIColor blueColor];

NSString *name = self.ingredientsBook.names[indexPath.item];
[self.selectedIngredientNames addObject:name];


}


The problem is that when I tap the first cell it's not possible to select the 16th or 17th.
Or if I tap the first three ones it's not possible to select the three last ones.
The
didSelectItemAtIndexPath
is not being called I suppose.

I feel that it has to be something really simple but I can't see it right now.

I tried to put
NSLogs
in
shouldSelectItemAtIndexPath
for understand if that method was called and the method is not being called at all. This happens when there's a distance of 16 cells between the selected one and the problematic one.

Here are other data source methods and isSelectedIndexPath:

-(BOOL)isSelectedIndexPath:(NSIndexPath *)indexPath{

for (NSIndexPath *test in selectedCellIndexPaths){
if (test == indexPath){
return YES;
}
}

return NO;
}

-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

return [self.ingredientsBook.names count];
}

-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView{

return 1;
}

-(BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath{

NSLog(@"%@", indexPath);

return YES;
}


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

self.searchButton.enabled = ([[collectionView indexPathsForSelectedItems] count] > 0);

ButtonCell *cell = (ButtonCell *)[collectionView cellForItemAtIndexPath:indexPath];
cell.backgroundColor = [UIColor blackColor];
cell.label.textColor = [UIColor whiteColor];

[selectedCellIndexPaths removeObject:indexPath];
NSString *name = self.ingredientsBook.names[indexPath.item];
[self.selectedIngredientNames removeObject:name];



}

Answer

I found two problems. The prepareForReuse method seemed to be screwing things up, so I just deleted it. The main problem though, was the way you were implementing isSelectedIndexPath:. As soon as it finds the first selected item as you loop through the items, it returns YES and exits the loop. What you want to do, is just check if the indexPath is contained in the selectedCellIndexPaths array:

-(BOOL)isSelectedIndexPath:(NSIndexPath *)indexPath{

    if ([selectedCellIndexPaths containsObject:indexPath]) {
        return YES;
    }else{
        return NO;
    }
}

Or, if you prefer to use a more succinct syntax, you can replace the if-else block with:

return  ([selectedCellIndexPaths containsObject:indexPath])? YES : NO;
Comments