Reused cells in a UICollectionView show multiple UIImageViews when they should only show one
The problem is that you keep adding views to the UICollectionViewCell
as they are being reused automagically by the UICollectionView
. So the old UIImageView
's are still on the cell as you are adding one more as the cellForItemAtIndexPath:
is called.
DO NOT USE addSubview:
!
Instead you could make a custom cell with all the views you want already in them. So that when the cellForItemAtIndexPath:
is called you only need to set the contents of this CustomCollectionViewCell instead.
This way it will certainly stop being corrupted.
How to build a CustomCell.
Step1: Create the .h & .m class.
CustomCell.h
#import <UIKit/UIKit.h>
@interface CustomCell : UICollectionViewCell
{
UIImageView *imageView;
}
@property (nonatomic, retain) UIImageView *imageView; //this imageview is the only thing we need right now.
@end
CustomCell.m
#import "CustomCell.h"
@implementation CustomCell
@synthesize imageView;
- (id)initWithFrame:(CGRect)aRect
{
if (self = [super initWithFrame:aRect])
{
//we create the UIImageView in this overwritten init so that we always have it at hand.
imageView = [UIImageView alloc] init];
//set specs and special wants for the imageView here.
[self addSubview:imageView]; //the only place we want to do this addSubview: is here!
//You wanted the imageView to react to touches and gestures. We can do that here too.
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)];
[tap setNumberOfTapsRequired:1];
[self addGestureRecognizer:tap];
//We can also prepare views with additional contents here!
//just add more labels/views/whatever you want.
}
return self;
}
-(void)onButtonTapped:(id)sender
{
//the response to the gesture.
//mind that this is done in the cell. If you don't want things to happen from this cell.
//then you can still activate this the way you did in your question.
}
Step2: Import it! Now that we created the CustomCell we can import it in the class we want to use it in.
Step3: Use it in action!
// creates the individual cells to go in the menu view
- (CustomCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// create collection view cell
CustomCell *cell = (CustomCell *)[collectionView dequeueReusableCellWithReuseIdentifier:@"CustomCell" forIndexPath:indexPath]; //this is the place where the CustomCell does his magic.
//Make sure to use the CustomCellReuseId that you register in the viewdidload/loadview (step4)
// add a button image
NSString * buttonPath=[[NSBundle mainBundle] pathForResource:@"button" ofType:@"png" inDirectory:[[buttons objectAtIndex:indexPath.row] objectForKey:@"name"]];
cell.imageView.image = [UIImage imageWithContentsOfFile:buttonPath]; //place the image on the CustemCell.imageView as we prepared.
// set tag to the indexPath.row so we can access it later
[cell setTag:indexPath.row]; //we don't need this to access the cell but I left this in for your personal want.
/*
* we can now do this from the CustomCell as well!
*
// add interactivity
UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)];
[tap setNumberOfTapsRequired:1];
[cell addGestureRecognizer:tap];
*/
// return the cell
return cell;
}
Step4: Register the cell to the collectionView
in the viewDidLoad / loadView add this line:
[_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"CustomCell"];
Step5: Enjoy! Your CustomCell is done. Now do whatever you like and don't forget to get some coffee too.
Right after
UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
Just add this line,
[[[cell contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
That Happen because you add every time a UIImageView
to your cell for fix this problem you have to Make a custom cell and then use it like take:
Custom.h
#import <UIKit/UIKit.h>
@interface CustomCell : UICollectionViewCell
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
Custom.m
#import "CustomCell.h"
@implementation CustomCell
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
@end
Your Controller
- (UICollectionViewCell *)collectionView:(UICollectionView *)cv cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CustomCell *cell = [cv dequeueReusableCellWithReuseIdentifier:@"CustomCell" forIndexPath:indexPath];
NSString * buttonPath=[[NSBundle mainBundle] pathForResource:@"button" ofType:@"png" inDirectory:[[buttons objectAtIndex:indexPath.row] objectForKey:@"name"]];
UIImage * button=[UIImage imageWithContentsOfFile:buttonPath];
[cell.imageView setImage:button];
return cell;
}
You have also to set 'CustomCell' like Identifier to the Cell in IB