it-roy-ru.com

Повторно используемые ячейки в 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;

}

Я могу предоставить больше кода, если требуется.

Как я могу остановить разрушение клеток?

29
Jimmery

Проблема в том, что вы продолжаете добавлять представления в UICollectionViewCell, так как они автоматически используются UICollectionView. Таким образом, старые UIImageView все еще находятся в ячейке, так как вы добавляете еще один, когда вызывается cellForItemAtIndexPath:.

НЕ ИСПОЛЬЗУЙТЕ addSubview:!

Вместо этого вы можете создать собственную ячейку со всеми нужными представлениями. Так что при вызове cellForItemAtIndexPath: вам нужно только установить содержимое этого CustomCollectionViewCell.

Таким образом, он наверняка перестанет быть испорченным.


Как построить CustomCell.

Step1 : Создать класс .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.

}

Step2 : Импортировать его! Теперь, когда мы создали CustomCell, мы можем импортировать его в класс, в котором мы хотим использовать его.

Step3 : Используйте это в действии!

// 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 : Зарегистрировать ячейку в collectionView

в viewDidLoad/loadView добавьте эту строку:

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

Step5 : Наслаждайтесь! Ваша CustomCell готова. Теперь делай что хочешь и не забудь выпить кофе тоже.

42
Totumus Maximus

Сразу после

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

Просто добавьте эту строку,

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

Это происходит потому, что вы каждый раз добавляете UIImageView в свою ячейку, чтобы решить эту проблему, вы должны создать собственную ячейку, а затем использовать ее как 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

Ваш контроллер

- (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
Mirko Catalano

Для тех, кто ищет ответ Swifty, добавьте эту функцию в свой класс CustomCell

override func prepareForReuse() {
    contentView.subviews.forEach({ $0.removeFromSuperview() })
    // replace contentView with the superview of the repeating content.
}
2
Bright Future
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;

   }
0
ShigaSuresh

Для тех, кто добавляет UICollectionView программно и имеет пользовательскую ячейку, другими словами, нет файла XIB, вам нужно добавить эту строку в viewDidLoad

[_collectionView registerClass:[CustomCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
0
Mayank Verma