user2289379
user2289379

Reputation:

Reusability issue on UICollectionView

I had worked with UITableView but I have never ever use of UICollectionView in my apps. So I want to create UICollectionView programmatically.

Following is my code:

UICollectionViewFlowLayout *layout =[[UICollectionViewFlowLayout alloc] init];
    _collectionView=[[UICollectionView alloc] initWithFrame:CGRectMake(0, 43, self.view.frame.size.width, self.view.frame.size.height - 84) collectionViewLayout:layout];
    [_collectionView setDataSource:self];
    [_collectionView setDelegate:self];
    [_collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
    layout.sectionInset = UIEdgeInsetsMake(5, 5, 5, 5);
    layout.minimumInteritemSpacing = 5;
    [_collectionView setBackgroundColor:self.view.backgroundColor];        
    [self.view addSubview:_collectionView];

Delegate and Datasource methods.

#pragma mark -
#pragma mark - UITableView Delegate Methods

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
    return 15;
}

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

    if (cell.selected)
        cell.backgroundColor = [UIColor lightGrayColor]; // highlight selection cell
    else
        cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background-grid.png"]]; // Default Cell

    UIImageView *imgPhoto = [[UIImageView alloc] init];
    imgPhoto.userInteractionEnabled = YES;
    imgPhoto.backgroundColor = [UIColor grayColor];
    imgPhoto.frame =  CGRectMake(3.5, 5, 90, 80);
    imgPhoto.clipsToBounds = YES;
    imgPhoto.image = [UIImage imageNamed:@"product.png"];
    [cell.contentView addSubview:imgPhoto];

    UILabel *lblCategoryTitle = [[UILabel alloc] init];
    [lblCategoryTitle  setFont: [UIFont fontWithName:@"OpenSans-Bold" size:14]];
    lblCategoryTitle.textAlignment = NSTextAlignmentCenter;
    lblCategoryTitle.frame = CGRectMake(3.5, 90, 90, 24);
    lblCategoryTitle.textColor = [UIColor blackColor];
    lblCategoryTitle.text = @"Product 1"; 
    lblCategoryTitle.backgroundColor = [UIColor clearColor];
    lblCategoryTitle.numberOfLines = 2;
    [cell.contentView addSubview:lblCategoryTitle];

    return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    return CGSizeMake(97, 118);
}

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

    UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
    datasetCell.backgroundColor = [UIColor lightGrayColor]; // highlight selection
}

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

    UICollectionViewCell *datasetCell =[collectionView cellForItemAtIndexPath:indexPath];
    datasetCell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background-grid.png"]]; // default cell
}

Then my screen Look like

enter image description here

Question 1 - Look at above screen, you will see that 1st and 3rd item is looking blur (see Product 1 ) then 2nd/middle item ? why this is happening ?

And whenever I scroll up/down UICollectionView then items are overwrite, Look at Next image

enter image description here

After looked this image, from my experience of UITableView, it's happening because of Reusability of cell of UICollectionView.

Question 2 - Then how can i solve it?

Please give my your suggestion and help me on this issue.

EDITED: (suggestion of @Dima)

Custom cell

.h file

#import <UIKit/UIKit.h>

@interface customeGridCell : UICollectionViewCell

@property (nonatomic, strong) UIImageView *imgPhoto;
@property (nonatomic, strong) UILabel *lblCategoryTitle;

@end

.m file

#import "customeGridCell.h"

@implementation customeGridCell

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
        self.imgPhoto = [[UIImageView alloc] init];
        self.imgPhoto.userInteractionEnabled = YES;
        self.imgPhoto.backgroundColor = [UIColor grayColor];
        self.imgPhoto.frame =  CGRectMake(3.5, 5, 90, 80);
        [self addSubview:self.imgPhoto];

        self.lblCategoryTitle = [[UILabel alloc] init];
        [self.lblCategoryTitle  setFont: [UIFont fontWithName:@"OpenSans-Bold" size:14]];
        self.lblCategoryTitle.textAlignment = NSTextAlignmentCenter;
        self.lblCategoryTitle.frame = CGRectMake(3.5, 90, 90, 24);
        self.lblCategoryTitle.textColor = [UIColor blackColor];
        self.lblCategoryTitle.backgroundColor = [UIColor clearColor];
        self.lblCategoryTitle.numberOfLines = 2;
        [self addSubview:self.lblCategoryTitle];
    }
    return self;
}

And code of cellForItemAtIndexPath

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

    if (cell.selected)
        cell.backgroundColor = [UIColor lightGrayColor]; // highlight selection cell
    else
        cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background-grid.png"]]; // Default Cell


    cell.imgPhoto.image =  [UIImage imageNamed:@"product.png"];
    cell.lblCategoryTitle.text = @"Product 1";

    return cell;
}

Upvotes: 2

Views: 2281

Answers (2)

Sunny Shah
Sunny Shah

Reputation: 13020

You can do it with two way.

Remove UILabel form view.

 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
    for (UILabel *lbl in cell.contentView.subviews)
    {
        if ([lbl isKindOfClass:[UILabel class]])
        {
            [lbl removeFromSuperview];
        }
    }
    UILabel *lblCategoryTitle =[[UILabel alloc]init];

    [lblCategoryTitle  setFont: [UIFont fontWithName:@"OpenSans-Bold" size:14]];
    lblCategoryTitle.textAlignment = NSTextAlignmentCenter;
    lblCategoryTitle.frame = CGRectMake(3.5, 90, 90, 24);
    lblCategoryTitle.textColor = [UIColor blackColor];
    lblCategoryTitle.text = @"Product 1";
    lblCategoryTitle.backgroundColor = [UIColor clearColor];
    lblCategoryTitle.numberOfLines = 2;
    [cell.contentView addSubview:lblCategoryTitle];
    return cell;
}

Use tag to get Label

 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
    UILabel *lblCategoryTitle =(UILabel *) [cell viewWithTag:5];
    if (!lblCategoryTitle) {
        lblCategoryTitle=[[UILabel alloc]init];
        [cell.contentView addSubview:lblCategoryTitle];

    }
    [lblCategoryTitle  setFont: [UIFont fontWithName:@"OpenSans-Bold" size:14]];
    lblCategoryTitle.tag=5;
    lblCategoryTitle.textAlignment = NSTextAlignmentCenter;
    lblCategoryTitle.frame = CGRectMake(3.5, 90, 90, 24);
    lblCategoryTitle.textColor = [UIColor blackColor];
    lblCategoryTitle.text = @"Product 1";
    lblCategoryTitle.backgroundColor = [UIColor clearColor];
    lblCategoryTitle.numberOfLines = 2;
    return cell;
}

Upvotes: 1

Dima
Dima

Reputation: 23624

The problem is in your collectionView:cellForItemAtIndexPath: method. You are adding those subviews every single time a cell is reused, on top of each other.

You should create a UICollectionViewCell subclass and add all of the extra subviews you want into its initializer. This will make sure they only get added once.

sample code:

Here is an example of how you would subclass UICollectionViewCell

@interface MyCustomCell : UICollectionViewCell

@property (nonatomic, strong) UILabel *customLabel;
@property (nonatomic, strong) UIImageView *customImageView;
@end


// in implementation file
- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) 
    {
        // initialize label and imageview here, then add them as subviews to the content view
    }
    return self;
}

Then when you are grabbing a cell you just do something like:

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

    if (cell.selected)
        cell.backgroundColor = [UIColor lightGrayColor]; // highlight selection cell
    else
        cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:@"background-grid.png"]]; // Default Cell

    cell.customImageView.image = // whatever
    cell.customLabel.text = // whatever

    return cell;
}

Upvotes: 3

Related Questions