简体   繁体   中英

UICollectionView not showing cells properly

I'm new to the UICollection View. Some cells are not showing up as can be seen in the image below. This is my code for setting it up, would be happy if someone could explain why some cells are missing. Also, when I scroll up and down the images in the cell will change for some reason (although in this screen shot I'm using the same images for all cells). The entire second and forth row are missing, and the middle column is missing. The intent is to have rows of three images per row adjacent to one another. Thanks!

   UICollectionViewFlowLayout *layout=[UICollectionViewFlowLayout new];
   self.collectionView=[[UICollectionView alloc] initWithFrame:Frame(0,225,1080, Denormalize(screenHeight) - 225) collectionViewLayout:layout];
   [self.collectionView setDataSource:self];
   [self.collectionView setDelegate:self];

   [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:@"cellIdentifier"];
   [self.collectionView setBackgroundColor:[UIColor redColor]];
   layout.minimumLineSpacing = 0;
   layout.minimumInteritemSpacing = 0;
   layout.sectionInset = UIEdgeInsetsMake(0,0,0,0);

   [self.view addSubview:_collectionView];

#pragma mark - CollectionView delegate
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
  return self.allVideos.count;
}

// The cell that is returned must be retrieved from a call to -dequeueReusableCellWithReuseIdentifier:forIndexPath:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
  UICollectionViewCell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:@"cellIdentifier" forIndexPath:indexPath];
//  cell.backgroundColor=[UIColor greenColor];

  NSDictionary *video = self.allVideos[indexPath.row];

  UIImageView *thumbnail = [UIImageView new];
  thumbnail.contentMode = UIViewContentModeScaleAspectFill;
  thumbnail.frame = cell.frame;
  thumbnail.clipsToBounds = YES;
  thumbnail.image = [UIImage imageNamed:@"DefaultAvatar.png"];
//  thumbnail.image = video[@"image"];
  [cell addSubview:thumbnail];

  return cell;
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
  return CGSizeMake(self.view.frame.size.width/3, self.view.frame.size.width/3);
}

在此输入图像描述

One major issue here is that you are adding a UIImageView as a subview in cellForItemAtIndexPath. This method runs every time a cell is dequeued, not every time a cell is initialized. This means that every time one of those cells is rendered like when the collection scrolls, a new subview is being added on top of the existing image view on the cell. This will very quickly cause major problems graphically and use way more memory then you intend to. The first thing I would do is subclass UICollectionViewCell and add your UIImageView to the subclass. You can then set the cell's image in that method but adding a subview in that particular spot is a really bad idea.

Here's my approach.

First, make a cell subclass and expose a method to set your image.

// MyCollectionViewCell.h

#import <UIKit/UIKit.h>

@interface MyCollectionViewCell : UICollectionViewCell

- (void)setImage:(UIImage *)image;

@end

// MyCollectionViewCell.m

#import "MyCollectionViewCell.h"

@interface MyCollectionViewCell ()

@property (strong, nonatomic) UIImageView *imageView;

@end

@implementation MyCollectionViewCell

-(instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setupImageView];
    }
    return self;
}

- (void)setupImageView
{
    UIImageView *imageView = [[UIImageView alloc]init];
    imageView.backgroundColor = [UIColor greenColor];
    [self addSubview:imageView];
    self.imageView = imageView;

    [imageView setTranslatesAutoresizingMaskIntoConstraints:NO];
    NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
    NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
    NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
    NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];

    [self addConstraints:@[leading, trailing, top, bottom]];

}

- (void)setImage:(UIImage *)image
{
    [self.imageView setImage:image];
}

@end

The layout constraints here are key. UICollectionViewCells, in my experience often have a frame of 0 when they are initialized which is why you are seeing a ton of empty boxes (the UIImageView on a new cell is being initialized with CGRectZero). The constraints will make sure that when they do eventually lay out correctly, the imageView will also resize itself to fit.

After this, register your custom cell class and then you can implement this in your CollectionViewController

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    MyCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
    [cell setImage:[UIImage imageNamed:@"emoji.jpg"]];
    // Configure the cell

    return cell;
}

Here's the before and after shots of setting the UIImageViewFrame explicitly

initWithFrame上的框架布局:

vs. using NSLayoutConstraints.

有约束的布局

For the hell of it, here's how to do the same thing in cellForItemAtIndexPath.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];

    NSInteger viewTag = 1000;
    UIImageView *imageView = (UIImageView *)[cell viewWithTag:viewTag];

    if (!imageView) {
        imageView = [[UIImageView alloc]init];
        imageView.tag = viewTag;
        [cell addSubview:imageView];

        [imageView setTranslatesAutoresizingMaskIntoConstraints:NO];
        NSLayoutConstraint *leading = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeLeading relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeLeading multiplier:1.0 constant:0];
        NSLayoutConstraint *trailing = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeTrailing relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeTrailing multiplier:1.0 constant:0];
        NSLayoutConstraint *top = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeTop multiplier:1.0 constant:0];
        NSLayoutConstraint *bottom = [NSLayoutConstraint constraintWithItem:imageView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:cell attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0];
        [cell addConstraints:@[leading, trailing, top, bottom]];
    }

    imageView.image = [UIImage imageNamed:@"emoji.jpg"];

    return cell;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM