Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically change cell size according to image in a UICollectionView

I am displaying dynamic images recieved from server in a horizontal collection view. When I set up the collectionview I set this:

-(void)setupCollectionView{
[self setupPageControlView];
self.screensCollectionView.delegate=self;
self.screensCollectionView.dataSource=self;
[self.screensCollectionView registerNib:[UINib nibWithNibName:@"FGAppScreensCollectionViewItemCell" bundle:nil] forCellWithReuseIdentifier:@"screenCell"];


UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
[flowLayout setMinimumInteritemSpacing:0.0f];
[flowLayout setMinimumLineSpacing:0.0f];
[flowLayout setItemSize:CGSizeMake(165, 255)];
//[self.screensCollectionView setPagingEnabled:YES];
[self.screensCollectionView setCollectionViewLayout:flowLayout];

}

For cellForRowAtIndexPath I download the image like this:

-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *cellIdentifier = @"screenCell";

FGAppScreensCollectionViewItemCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];

NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:[self.imageURLArray objectAtIndex:indexPath.row]]];

UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[spinner startAnimating];
[spinner setFrame:CGRectMake(50, 100, 20, 20)];
[cell.contentView addSubview:spinner];
[cell.screenImageView setImageWithURLRequest:urlRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
    //STOP THE SPINNER
    for (UIView* view in [cell.contentView subviews]) {
        if ([view isKindOfClass:[UIActivityIndicatorView class]]) {
            [view removeFromSuperview];
        }
    }
    cell.screenImageView.image = image;

} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
    //
}];
[cell.screenImageView setImageWithURL:[NSURL URLWithString:[self.imageURLArray objectAtIndex:indexPath.row]]];
if (self.delegate) {
      UITapGestureRecognizer* g = [[UITapGestureRecognizer alloc] initWithTarget:self.delegate action:@selector(showPopUpImageView:)];
      [cell.screenImageView addGestureRecognizer:g];
}

return cell;

}

However there are both portrait and landscape images displayed in the collection view. Portrait Images are displaying just fine but landscape images are appearing to small in the collectionview. What I need to do is resize the cell according to the image size so that they fill up correct aspect ratio?

I added method like this below but the problem is it gets called for all cells at once in the beginning and won't be called once I download the image in cellForRowAtIndexPath method:

    - (CGSize)collectionView:(UICollectionView *)collectionView
              layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath

{

return CGSizeMake(165, 255);

}

Hence, I am wondering how can I achieve this feature, Let me know if more information is needed in this regard?

like image 822
tech savvy Avatar asked Feb 03 '14 10:02

tech savvy


2 Answers

In -setImageWithURLRequest:..., when the image loads cache it in a hash table, and then call -reloadItemsAtIndexPaths: with the current image path, to reload the cell and thus causing the CollectionView to re-check what size the cell should be.

Make sure you consult the hash table when looking up the image. This will also save you extra network accesses in cases where the collectionView items scroll offscreen and back on again.

Note I am worried that if you’re using a UICollectionReusableView subclass your code can fail, because cells can be re-used before their images ever load, so the images will load in the wrong place.

like image 118
Wil Shipley Avatar answered Oct 18 '22 15:10

Wil Shipley


However add an delegate method of UICollectionView.

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath
{
    UIImageView *image = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[arryOfImg objectAtIndex:indexPath.row]]];

    //You may want to create a divider to scale the size by the way..
    return CGSizeMake((image.frame.size.width)/4.0, (image.frame.size.height)/4.0);
}
like image 37
Darshan Mothreja Avatar answered Oct 18 '22 14:10

Darshan Mothreja