SanitLee
SanitLee

Reputation: 1253

Messing UIButton in each UICollectionViewCell in Scrolling Filmstrip

This is a follow-up question to my previous one and this time I have a problem with UIButton that I have added in each UICollectionViewCell. Before diving into the problem, let me brief out all I've got so far.

Here's the basic rundown of how my UICollectionView in Scrolling Filmstrip style within UITableView works:

So far, I've been able to add UIButton in each UICollectionViewCell and when I tap the UIButton its image will change to checked mark but the problem occurs when I scroll up/down. Once the cell with checked mark UIButton is off-screen and scrolled back on-screen again, UIButton image starts to get messed around. For example, when UIButton image in cell1 should be checked mark but it's not. Instead checked mark will be appeared in another cell.

Here below is my relevant code:

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    PostsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"PostsCollectionViewCell" forIndexPath:indexPath];
    NSDictionary *cellData = [self.collectionData objectAtIndex:[indexPath row]];

    cell.postTextLabel.text = [cellData objectForKey:@"text"];
    cell.locationNameLabel.text = [cellData objectForKey:@"locationName"];

    //  >>> Select Button <<<
    UIButton *selectButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [selectButton setFrame:CGRectMake(110, 150, 20, 20)];
    [selectButton setImage:[UIImage imageNamed:@"uncheckedDot.png"] forState:UIControlStateNormal];
    [selectButton setImage:[UIImage imageNamed:@"checkedDot.png"] forState:UIControlStateSelected];
    [cell.contentView addSubview:selectButton];
    [selectButton addTarget:self
                   action:@selector(buttonPressed:)
         forControlEvents:UIControlEventTouchUpInside];
    //  >>> End Select Button <<<<

    return cell;
}

//  >>> Select Button Method <<<
-(void) buttonPressed:(UIButton *)sender
{
    if([sender isSelected]){
        //...
        [sender setSelected:NO];
    } else {
        //...
        [sender setSelected:YES];
    }
}

Any help would be greatly appreciated! Thanks in advance.

enter image description here

Upvotes: 1

Views: 388

Answers (2)

Ishan Handa
Ishan Handa

Reputation: 2281

Maintain in your Data source which cell is to be selected by adding a key for each data source dict. For example:@"isSelected"

Then in cellForRowAtIndexPath:

if ([[cellData valueForKey:@"isSelected"] boolValue]) {
    [selectButton setSelected:NO];
} else {
    [selectButton setSelected:YES];
}

and in your -(void) buttonPressed:(UIButton *)sender Method:

CGPoint point = [self.collectionView convertPoint:CGPointZero fromView:sender];
NSIndexPath  *indexPath = [self.collectionView indexPathForItemAtPoint:point];
NSDictionary *cellData = [self.collectionData objectAtIndex:[indexPath row]];

if ([[cellData valueForKey:@"isSelected"] boolValue]) {
     [cellData setValue:@"false" forKey:@"isSelected"];
} else {
    [cellData setValue:@"true" forKey:@"isSelected"];
}

[self.framesCollectionView reloadItemsAtIndexPaths:@[indexPath]];

AND

In your cellForRowAtIndexPath set a tag for the UIButton. Then before adding a UIButton as subview to the cell's contentView check if a view with this tag already exists. In case the cell has been reused, just use the already existing button.

Upvotes: 2

Arthur Gevorkyan
Arthur Gevorkyan

Reputation: 2107

Man, you should be aware that cells (both for UITableView and UICollectionView) are reused via the reuse deque under the hood of UIKit and are not obligated to keep their state consistent with regard to their position in a table view or a collection view. What you need to do is to make sure that the return value of dequeueReusableCellWithReuseIdentifier: is then properly initialized (or, in your case, re-initialized) in accordance with the state of your data model. Basically, you need to store the state of your "checkmarks" (or "checkboxes", what have you) in an array or any other data structure. Then, when you call dequeueReusableCellWithReuseIdentifier:, you should apply that stored state to the return value (the cell you're going to return for the collection view) you just got. Hope it's explained good enough. Good luck.

Upvotes: 2

Related Questions