Dale Townsend
Dale Townsend

Reputation: 691

Change the image of a specific cell inside a UICollectionView

I have a 5x5 grid of cells in a UICollectionView, each with an image set like this:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    CollectionViewCell *cell = (CollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"circleCell" forIndexPath:indexPath];

    imageArray = [[NSMutableArray alloc]init];
    for (int i=1; i<=12; i++) {
        UIImage *imageToAdd = [UIImage imageNamed:[NSString stringWithFormat:@"%i", i]];
        [imageArray addObject:imageToAdd];
    }

    self.cellImageView = [[UIImageView alloc] initWithFrame:[self getCircleSize]];
    int i = arc4random() % 12;
    [self.cellImageView setImage:[imageArray objectAtIndex:i]];
    [cell addSubview:self.cellImageView];
    cell.tag = i;
    return cell;
}

Each image is a circle of a random color - 1.png to 12.png. I am detecting taps on a specific cell, and then getting it's color and position in the collection view:

UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
NSIndexPath *indexPath = [collectionView indexPathForCell:cell];

self.firstCircleSection = indexPath.section;
self.firstCircleRow = indexPath.row;
self.firstCircleIndex = (indexPath.section * 5) + (indexPath.row + 1);

self.firstCircleNum = (int)cell.tag;
//I have a dictionary with colors and keys, e.g 1 Yellow, 2 Blue, 3 Red. This line gets the color:
NSString *dotColor = [NSString stringWithFormat:@"Colour: %@", [self.colorDict objectForKey:[NSString stringWithFormat:@"%ld", self.firstCircleNum]]];

Then for the second circle tap of another circle, I am calculating what the new color of each circle will be (a color in the middle of the two selected colors):

UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
NSIndexPath *indexPath = [collectionView indexPathForCell:cell];

self.secondCircleSection = indexPath.section;    
self.secondCircleRow = indexPath.row;    
self.secondCircleIndex = (indexPath.section * 5) + (indexPath.row + 1);
self.secondCircleNum = (int)cell.tag;

NSString *circleColor = [NSString stringWithFormat:@"Colour: %@", [self.colorDict objectForKey:[NSString stringWithFormat:@"%ld", self.secondCircleNum]]];

NSInteger i = (self.firstCircleNum + self.secondCircleNum)/2;
NSString *dotColor = [NSString stringWithFormat:@"Colour: %@", [self.colorDict objectForKey:[NSString stringWithFormat:@"%ld", i]]];

// Labels on the view for showing what the colors mix like
colorLabel2.text = circleColor;
positionLabel2.text = [NSString stringWithFormat: @"Position: %ld", self.secondCircleIndex];
mixedColorLabel.text = [NSString stringWithFormat:@"New %@", dotColor];

NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:self.firstCircleRow inSection:self.firstCircleSection];
NSInteger theFirstCircleIndex = (indexPath2.section * 5) + (indexPath2.row + 1);
NSIndexPath *indexPath3 = [NSIndexPath indexPathForRow:self.secondCircleRow inSection:self.secondCircleSection];
NSInteger theSecondCircleIndex = (indexPath3.section * 5) + (indexPath3.row + 1);

// Get a reference to the two cells
UICollectionViewCell *firstCircle = [collectionView dequeueReusableCellWithReuseIdentifier:@"circleCell" forIndexPath:indexPath2];
UICollectionViewCell *secondCircle = [collectionView dequeueReusableCellWithReuseIdentifier:@"circleCell" forIndexPath:indexPath3];

My question is, once I have done all this, how can I change the image of those two cells - firstCircle and secondCircle? I have a property on the custom CollectionViewCell, cellImage, but am unable to access it with: firstCircle.cellImage. I want to change the image on both cells.

Upvotes: 0

Views: 2471

Answers (1)

pbasdf
pbasdf

Reputation: 21536

In your cellForItemAtIndexPath: method, you are creating a new UIImageView, setting its image from your array, and adding it as a subview of the cell. This is different from the cellImage property of the cell. To fix this:

Either: If you have configured your custom CollectionViewCell in a storyboard (i.e. added an image view to the prototype cell, and hooked it up to the CollectionViewCell's cellImage outlet), then you needn't add the extra UIImageView you can just use:

cell.cellImage.image = [imageArray objectAtIndex:i];

Or: If it's not configured in a storyboard (or the CollectionViewCell initialiser), then keep your existing code, but set cell.cellImage to point to the imageView you created:

cell.cellImage = self.cellImageView;

Next: In your other code (which I assume is in didSelectItemAtIndexPath?), the following line tells the compiler that cells are of the base UICollectionViewCell class:

UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];

But you want the compiler to know that these cells are actually your custom CollectionViewCell class. So amend the line to:

CollectionViewCell *cell = (CollectionViewCell *)[collectionView cellForItemAtIndexPath:indexPath];

(and similarly elsewhere). That done, the compiler should then let you use the cellImage property without problem.

Now, to get a reference to the cells for indexPath2 and indexPath3, don't use the dequeueReusableCellWithIdentifier: method, use cellForItemAtIndexPath: (just as you do in the first line):

CollectionViewCell *firstCircle = [collectionView cellForItemAtIndexPath:indexPath2];
CollectionViewCell *secondCircle = [collectionView cellForItemAtIndexPath:indexPath3];

You can then manipulate their images with firstCircle.cellImage.image etc.

Also, there is some redundancy in your code: with these lines:

UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
NSIndexPath *indexPath = [collectionView indexPathForCell:cell];

you are getting the cell for a given indexPath, and then getting the indexPath for that cell - it will be the same. So you can delete the second of these lines. Also, in the code which handles secondCircle, indexPath3 is the same as indexPath, and secondCircle will actually be the cell that you set at the start of the code. So just use:

CollectionViewCell *secondCircle = cell;

Finally, your cellForItemAtIndexPath loads the imageArray every time it is called - which is unnecessary. I would use a different method to load these images - perhaps the viewDidLoad method.

Upvotes: 2

Related Questions