Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UICollectionView with dynamic cell content - get cell to remember state

I have a UICollectionView that contains dynamic content. The problem I am having is that when the cell is dequeued it forgets its state. In my - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath I have a boolean value that when it is true, it changes to a true image, but when it is false, it changes to a false image. However when I scroll down and back up, the cells forget there state. Is there a way to make a cell remember its state? Here is what is inside my

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

    SalesCollectionViewCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"Cell" forIndexPath:indexPath];
    SaleImage * saleImage = [self.SaleObjs objectAtIndex:indexPath.row];
    cell.bgImageView.image = [UIImage imageNamed:saleImage.imageName];
    if (saleImage.isBookable) {
        cell.isBookable = YES;
    }
    else{
        cell.isBookable=NO;
    }

return cell;
}

I have a remedy for this but it effects performance. I add this to my custom cell;

-(void)prepareForReuse{
    [super prepareForReuse];


    [self setNeedsLayout];
}

Here is my collection view cell;

@implementation SalesCollectionViewCell


- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {

        // Initialization code
        self.layer.cornerRadius = 6.0;
        self.bgImageView = [[UIImageView alloc] init];
        self.book = [[UILabel alloc] init];      
        [self.contentView insertSubview:self.bgImageView atIndex:0];


         return self;
}

-(void)layoutSubviews{

    [super layoutSubviews];

    if (self.isBookable) {
        self.book.frame =CGRectMake(0, self.bounds.size.height - 41, 140, 41);
        self.book.text = @"Book this Item";
        self.book.textColor = [UIColor whiteColor];
        self.book.adjustsFontSizeToFitWidth=YES;
        self.book.textAlignment = NSTextAlignmentCenter;
        self.book.backgroundColor= [UIColor darkGrayColor];
        self.book.font = [UIFont fontWithName:kAppFont size:17.0];
        [self.contentView insertSubview:self.book atIndex:2];

        self.bgImageView.frame =CGRectMake(0, 0, 140, self.bounds.size.height - self.book.bounds.size.height);


    }
    else{
        self.bgImageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);

    }



}

-(void)prepareForReuse{
    [super prepareForReuse];

    [self.book removeFromSuperview];
    [self setNeedsLayout];


}
like image 383
DevC Avatar asked Dec 20 '22 13:12

DevC


2 Answers

Cells should not "remember" their state; collection view or table view data source should. In the respective cellForIndexPath method, you should set the current state of the cell and let it configure itself as needed.

like image 149
Léo Natan Avatar answered Dec 22 '22 03:12

Léo Natan


As @iphonic said, the isBookable property should be (re)moved from the cell completely. Cells in a UICollectionView are being reused most of the time, so even though your saleImage.isBookable is in the correct state your cell.isBookable is probably not.

I would do the following:

if(saleImage.isBookable){
  self.bgImageView.frame = CGRectMake(0, 0, 140, self.bounds.size.height - self.book.bounds.size.height);
  cell.bgImageView.image = [UIImage imageNamed:saleImage.imageName];
  cell.book.hidden = NO;
}
else{
 self.bgImageView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
 cell.bgImageView.image = nil;
 cell.book.hidden = YES;
}

[cell layoutIfNeeded];

inside collectionView: cellForItemAtIndexPath:.

I would also have finished setting up the book UILabel inside initWithFrame and have it initially hidden. Something like:

- (id)initWithFrame:(CGRect)frame{
    self.layer.cornerRadius = 6.0;
    self.bgImageView = [[UIImageView alloc] init];
    [self.contentView insertSubview:self.bgImageView atIndex:0];

    self.book = [[UILabel alloc] initWithFrame:CGRectMake(0, self.bounds.size.height - 41, 140, 41)];      

    self.book.text = @"Book this Item";
    self.book.textColor = [UIColor whiteColor];
    self.book.adjustsFontSizeToFitWidth=YES;
    self.book.textAlignment = NSTextAlignmentCenter;
    self.book.backgroundColor= [UIColor darkGrayColor];
    self.book.font = [UIFont fontWithName:kAppFont size:17.0];
    self.book.hidden = YES;

    [self.contentView insertSubview:self.book atIndex:2];
}

Then you would not need to override layoutSubviews.

Hope that helps.

like image 21
Don Miguel Avatar answered Dec 22 '22 04:12

Don Miguel