Повторно используемые ячейки в UICollectionView показывают несколько UIImageViews, когда они должны показывать только один
У меня проблема с моим UICollectionView
. Первоначально он отображает тонкий, показывая сетку ячеек, каждая ячейка с одним UIImageView
. Эти UIImageViews
показывают PNG с прозрачностью, которые хранятся в комплекте приложений.
Моя проблема в том, что после прокрутки UICollectionView
некоторые из ячеек кажутся поврежденными.
Коррумпированная ячейка показывает несколько изображений, уложенных друг на друга, верхнее большинство изображений - это то, которое должно отображаться, а изображения под ними - те, которые должны использоваться в других ячейках.
Мое лучшее предположение заключается в том, что это связано с тем, как ячейки внутри UICollectionView
повторно используются, но я открыт для предложений.
Это код делегата, который я использую для создания ячеек в UICollectionView
:
// 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;
}
Я могу предоставить больше кода, если это необходимо.
Как я могу остановить повреждение ячеек?
Ответы
Ответ 1
Проблема заключается в том, что вы продолжаете добавлять представления к UICollectionViewCell
, поскольку они автоматически используются с помощью UICollectionView
. Таким образом, старые UIImageView
все еще находятся в ячейке, поскольку вы добавляете еще один символ, когда вызывается cellForItemAtIndexPath:
.
НЕ ИСПОЛЬЗУЙТЕ addSubview:
!
Вместо этого вы можете создать пользовательскую ячейку со всеми представлениями, которые вы уже хотите в них. Так что, когда вызывается cellForItemAtIndexPath:
, вам нужно только установить содержимое этого CustomCollectionViewCell.
Таким образом, он, безусловно, перестанет быть поврежденным.
Как создать CustomCell.
Шаг1. Создайте классы .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.
}
Шаг2: импортируйте его!
Теперь, когда мы создали CustomCell, мы можем импортировать его в класс, который мы хотим использовать.
Шаг 3: используйте его в действии!
// 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;
}
Шаг4: зарегистрируйте ячейку в коллекцииView
в viewDidLoad/loadView добавьте эту строку:
[_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"CustomCell"];
Шаг 5: наслаждайтесь!
Ваш CustomCell сделан. Теперь сделайте все, что захотите, и не забудьте также выпить кофе.
Ответ 2
Сразу после
UICollectionViewCell * cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cell" forIndexPath:indexPath];
Просто добавьте эту строку,
[[[cell contentView] subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
Ответ 3
Что происходит, потому что вы добавляете каждый раз, когда a 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
Ответ 4
Для тех, кто ищет ответ Swifty, добавьте эту функцию в класс CustomCell
:
override func prepareForReuse() {
contentView.subviews.forEach({ $0.removeFromSuperview() })
// replace contentView with the superview of the repeating content.
}
Ответ 5
Для тех, кто добавляет UICollectionView программно и имеет пользовательскую ячейку, другими словами, нет XIB файла, тогда вы должны добавить эту строку в viewDidLoad
[_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
Ответ 6
Это для удаления дубликата текста с метки в 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;
}
Ответ 7
for (UIView *prevSubview in cell.contentView.subviews) {
[prevSubview removeFromSuperview];
}