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.
Cell is being overzealously reused
UICollectionViewCell
s are reused by the system, so you need to handle the possibility of a cell being reused in the prepareForReuse
method in UICollectionViewCell
, by clearing everything from the cell (setting the image to nil etc.)
Here is the doc for UICollectionReusableView that declares that
Here is the doc for UICollectionView You can see in that doc, for the method dequeueReusableCellWithReuseIdentifier:forIndexPath:
it talks about calling prepareForReuse
if there is an available cell to reuse.
Reusable UICollectionViewCell not changing UIImageView property (showing duplicates)
First of all, you are removing the image view from its superview in prepareForReuse()
but you never add it back. init()
will not be called when reusing a cell, and neither will config()
. Unless you have a specific reason for it, you shouldn't need to remove the image view from its superview. Just setting its image to nil should be enough.
Also, set a breakpoint and verify that friends[path].userAvatar
returns a valid path to an image.
UIImageView spills out of collection view cell
By default the estimate size
is set to Automatic
. Set it to None
Related Topics
React-Native iOS Not Showing Images (Pods Issue)
Gem Native Extension Error While Installing Cocoapods
How to Activate Tcp Keepalive on Apple iOS Devices
Swift Calculate Md5 Checksum for Large Files
"Unable to Validate Your Application Error" While Uploading a New Version of iOS App
How to Wait for Method That Has Completion Block (All on Main Thread)
Firebase Retrieving Data in Swift
Dispatchqueue Crashing with Main.Sync in Swift
How to Customize Uirefreshcontrol with Different Image and Position
How to Change Space Between Cells in Uicollectionview
Customizing the Colors of a Uisegmentedcontrol
How to Detect If the Currently Running App Was Installed from the App Store
How to Upload Video to Server from Iphone
Swift Images Change to Wrong Images While Scrolling After Async Image Loading to a Uitableviewcell
How to Programmatically Dismiss Uialertcontroller Without Any Buttons
"Can't Find Model for Source Store" Occurring During iPhone "Automatic Lightweight Migration"
Opening Word,Excel, and PDF Files Without Using Uiwebview on iOS
Swiftui - How to Get Didset to Fire When Changing a @Published Struct