当UICollectionView中的重用单元格显示多个UIImageView时,应该只显示一个

我有我的UICollectionView有问题。 最初它显示正常,显示单元格的网格,每个单元格与一个单一的UIImageView 。 这些UIImageViews显示了存储在应用程序包中的具有透明度的PNG。

我的问题是,一旦UICollectionView已经滚动,一些单元格似乎已损坏。

腐败的单元格显示了多个图像堆叠在一起,最上面的图像是它应该显示的图像,下面的图像是应该在其他单元格中使用的图像。

我最好的猜测是,这与UICollectionView中的单元格被重用的方式有关,但我愿意提供build议。

这是我用来在UICollectionView创build单元格的委托代码:

 // creates the individual cells to go in the menu view - (UICollectionViewCell*) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { // create collection view cell UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]; // create a uiview where we can place all views that need to go into this cell UIView * contents=[[UIView alloc] initWithFrame:cell.contentView.bounds]; [contents setBackgroundColor:[UIColor clearColor]]; [cell.contentView addSubview:contents]; // add a button image NSString * buttonPath=[[NSBundle mainBundle] pathForResource:@"button" ofType:@"png" inDirectory:[[buttons objectAtIndex:indexPath.row] objectForKey:@"name"]]; UIImage * button=[UIImage imageWithContentsOfFile:buttonPath]; UIImageView * buttonView=[[UIImageView alloc] initWithImage:button]; [buttonView setContentMode:UIViewContentModeScaleAspectFit]; [buttonView setFrame:contents.bounds]; [contents addSubview:buttonView]; // set tag to the indexPath.row so we can access it later [cell setTag:indexPath.row]; // add interactivity UITapGestureRecognizer * tap=[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onButtonTapped:)]; [tap setNumberOfTapsRequired:1]; [cell addGestureRecognizer:tap]; // return the cell return cell; } 

如果需要,我可以提供更多的代码。

我怎样才能阻止细胞腐化?

问题在于,您继续向UICollectionViewCell添加视图,因为它们是由UICollectionView自动重新使用的。 所以旧的UIImageView仍然在单元格上,因为您正在调用cellForItemAtIndexPath:添加一个。

不要使用addSubview:

相反,你可以用自己想要的所有视图来制作自定义单元格。 因此,当调用cellForItemAtIndexPath:时,您只需要设置此CustomCollectionViewCell的内容。

这样它肯定会停止被破坏。


如何构build一个CustomCell。

第一步 :创build.h&.m类。

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. } 

第二步 :导入它! 现在我们创build了CustomCell,我们可以将其导入到我们想要使用的类中。

第三步 :在行动中使用它!

 // 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; } 

第四步 :注册单元到collectionView

在viewDidLoad / loadView中添加这一行:

 [_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"CustomCell"]; 

第五步 :享受! 你的CustomCell完成了。 现在做任何你喜欢的,不要忘了也要喝点咖啡。

之后

 UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath]; 

只要加上这一行,

 [[[cell contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)]; 

发生这种情况,因为你每次添加一个UIImageView到你的单元格来解决这个问题,你必须做一个自定义的单元格,然后像使用它:

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 

你的控制器

 - (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; } 

您还需要将标识符“CustomCell”设置为IB中的单元格

对于那些正在寻找一个Swifty答案,添加此函数到您的CustomCell类:

 override func prepareForReuse() { contentView.subviews.forEach({ $0.removeFromSuperview() }) // replace contentView with the superview of the repeating content. } 

对于任何以编程方式添加UICollectionView并拥有自定义单元的人,换句话说,不需要XIB文件,那么您必须将此行添加到viewDidLoad

 [_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cellIdentifier"]; 
 This is for removing duplicate text from label in uicollectionviewcell. // Viewdidload [_collectionView registerClass:[UICollectionviewcell class] forCellWithReuseIdentifier:@"cellIdentifier"]; //in this method create label like this -(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 *nameLbl=[[UILabel alloc] initWithFrame:CGRectMake(0, 10, 50, 20)]; nameLbl.text=[Array objectAtIndex:indexpath.row]; nameLbl.textColor=[UIColor whiteColor]; [cell.contentView addSubview:nameLbl]; return cell; } 
 for (UIView *prevSubview in cell.contentView.subviews) { [prevSubview removeFromSuperview]; }