1

I need to make a Pinterest style newsfeed. I have created a collection view with 2 columns. I am downloading the photos async in cellForItemAtIndexPath:

  - (UICollectionViewCell *)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
     TFNewsObject *obj = [self.sortedDataSource objectAtIndex:indexPath.row];
     [imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached
                            completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                                obj.tfImage = image;                             
                            }];
     return cell;
    }

The problem is that I need to set the size of the cell in heightForItemAtIndexPath and there the image has not been downloaded yet because it did not enter cellForItemAtIndexPath yet. I am setting a fixed size of 100 for the height. I need to somehow trigger heightForItemAtIndexPath after I've downloaded the image in cellforItemAtIndexPath.

Another thing that I've tried is downloading the image in heightForItemAtIndexPath synchronous and calculating the height after the image downloaded. In that manner it displays correctly with each cell with a different height depending on the image, but it takes forever to load all the images.

Is there a way to modify the cell's height after I've downloaded the image? Thanks!

  • I would go with a variation of your second approach: asynchronous download of your images, then calculate the height of that image, then update your collectionView, then when the user scrolls down to the image or up or whatever, then you load your image into memory. A neat trick is to calculate the average colour of the image and colour the background of the cell. – Johnny Rockex May 12 '17 at 10:20

3 Answers3

1

Try this

[imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached
                            completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                                obj.tfImage = image; 
                                   collectionView .reloadItems(at: [indexPath])

                            }];
KKRocks
  • 8,222
  • 1
  • 18
  • 84
0

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

Another solution that you can try is to invalidate the collection view layout when the image is downloaded.

- (UICollectionViewCell *)collectionView:(UICollectionView*)collectionView cellForItemAtIndexPath:(NSIndexPath*)indexPath {
 TFNewsObject *obj = [self.sortedDataSource objectAtIndex:indexPath.row];
 [imageView sd_setImageWithURL:url placeholderImage:nil options:SDWebImageRefreshCached
                        completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
                             [self.collectionView.collectionViewLayout invalidateLayout];  
                        }];
 return cell;
}

After this return a appropriate size in the delegate method:

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return /* size */;
}
Tejas K
  • 682
  • 11
  • 28
0

I got into similar problem while i developed something similar to pinterest layout.

Even we had a lag while downloading images asynchronously and once the download is done refreshing cell by cell will blow away the user and will lead to UI jerks.

The solution which i could suggest is,

For example when the post is created with the image, Calculate the size (width and height) of the image and save it in the DB. So the size of the image is available before the image is downloaded or cached and we could scale the cell to the height of the image and display a default image and when the actual image is cached or downloaded it would silently replace the default image without any UI jerks.

If you are using services like cloudinary then you can avoid the pain of storing the image size (height and width). The cloudinary api will give you the height and width of the image.

Pavan kumar C
  • 393
  • 1
  • 4
  • 15