web-dev-qa-db-fra.com

Sélection de cellule UICollectionview

j'ai fait une grille d'images et afin de montrer sa sélection, j'ai dessiné une bordure pour l'image sélectionnée. mais le problème est que lorsque je sélectionne une image en haut et que je fais défiler la grille des images, une autre image en bas semble également être sélectionnée. Voici l'extrait de code:

UINib *cellNib = [UINib nibWithNibName:@"collectionCell" bundle:nil];
[self.collectionView registerNib:cellNib forCellWithReuseIdentifier:@"cellCV"];

UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setItemSize:CGSizeMake(95, 95)];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionVertical];

[self.collectionView setCollectionViewLayout:flowLayout];

Ci-dessus a été ajouté dans viewDidLoad avec la cellule de vue de collection conçue dans nib.

et mis en œuvre par les délégués suivants:

-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{   
selectedImageIndex = indexPath.row;
[collectionView reloadData]; 
}

-(CollectionCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UIImage *img = [imageArray objectAtIndex:indexPath.row];

static NSString *cellIdentifier = @"cellCV";
CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:   
cellIdentifier forIndexPath:indexPath];
cell.imageView.image = img;
cell.imageView.tag = indexPath.row;
UIImageView *imgView = (UIImageView *)[cell viewWithTag:indexPath.row];
if (indexPath.row == selectedImageIndex) {
    imgView.layer.borderWidth =  4.0;
    imgView.layer.borderColor = [UIColor redColor].CGColor;
    NSLog(@"selected indexpath: %d", indexPath.row);
}
else {
    imgView.layer.borderWidth =  0.0;
    imgView.layer.borderColor = nil;
}
return cell;    
}

je pourrais deviner que quelque chose ne va pas avec la réutilisation de la cellule, mais je ne suis pas sûr et je ne pourrais pas avoir une idée pour le résoudre . En attente de tout type d'aide et de suggestions.

Merci d'avance.

18
XiOS

Je ne vois pas pourquoi cela se produirait. Je ne crois pas que le problème réside dans l'utilisation de row contre item, bien que vous devriez vraiment utiliser item. Cependant, je peux imaginer que si votre vue de collection comporte plus d'une variable section, le fait de ne regarder que la variable row/item mais de ne pas tenir compte de section constituerait un problème (c'est-à-dire qu'il sélectionnerait le même nombre item dans tous section).

Pour couper le nœud gordien, je suggérerais de conserver la NSIndexPath de l'élément sélectionné, puis de l'utiliser comme base de comparaison. Cela facilite également le rendu d'une optimisation dans didSelectItemAtIndexPath. Quoi qu'il en soit, commencez par définir votre propriété:

@property (nonatomic, strong) NSIndexPath *selectedItemIndexPath;

Et puis implémentez cellForItemAtIndexPath et didSelectItemAtIndexPath:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *cellIdentifier = @"Cell";

    CollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

    cell.imageView.image = ...

    if (self.selectedItemIndexPath != nil && [indexPath compare:self.selectedItemIndexPath] == NSOrderedSame) {
        cell.imageView.layer.borderColor = [[UIColor redColor] CGColor];
        cell.imageView.layer.borderWidth = 4.0;
    } else {
        cell.imageView.layer.borderColor = nil;
        cell.imageView.layer.borderWidth = 0.0;
    }

    return cell;
}

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
    // always reload the selected cell, so we will add the border to that cell

    NSMutableArray *indexPaths = [NSMutableArray arrayWithObject:indexPath];

    if (self.selectedItemIndexPath)
    {
        // if we had a previously selected cell

        if ([indexPath compare:self.selectedItemIndexPath] == NSOrderedSame)
        {
            // if it's the same as the one we just tapped on, then we're unselecting it

            self.selectedItemIndexPath = nil;
        }
        else
        {
            // if it's different, then add that old one to our list of cells to reload, and
            // save the currently selected indexPath

            [indexPaths addObject:self.selectedItemIndexPath];
            self.selectedItemIndexPath = indexPath;
        }
    }
    else
    {
        // else, we didn't have previously selected cell, so we only need to save this indexPath for future reference

        self.selectedItemIndexPath = indexPath;
    }

    // and now only reload only the cells that need updating

    [collectionView reloadItemsAtIndexPaths:indexPaths];
}

En passant, notez que je ne plaisante pas avec la propriété tag (je n'y vois aucune valeur). Notez également que plutôt que de recharger l'intégralité de la vue de collection, je ne fais que recharger la cellule sélectionnée (et s'il y avait une cellule précédemment sélectionnée, celle-ci aussi), ce qui devrait être plus efficace.

41
Rob

Ce code est dans Swift 3:

if self.selectedItemIndexPath != nil && indexPath.compare(self.selectedItemIndexPath) == .orderedSame {
    cell.imageView!.layer.borderColor = UIColor.red.cgColor
    cell.imageView!.layer.borderWidth = 4.0
} else {
    cell.imageView!.layer.borderColor = nil
    cell.imageView!.layer.borderWidth = 0.0
}

return cell
1
Phung Du