当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]; }