Search code examples
iosobjective-cuitableviewuiimageautoresize

Dynamic cell size depending on the size of Image fetched from URL in iOS


INFO:

I have Tableview which is having cells with Imageview. In that Imageview, I am fetching Different images from imgURL...

What I need:

I need Dynamic height of cell according to the image height fetched from imgURL.

NOTE: I am not using auto layout, but i am using auto resizing.

What i did till now:

I have used asynchronous Image loading in ImageView. ( by #import "UIImageView+WebCache.h")

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{

    HomePostCell *cell=[tableView dequeueReusableCellWithIdentifier:strIdentifier];
    if (cell==nil) {
        cell = [[HomePostCell alloc]
                initWithStyle:UITableViewCellStyleDefault
                reuseIdentifier:strIdentifier];
    }

    [cell.imgMain sd_setImageWithURL:[NSURL URLWithString:strImgURL] placeholderImage:[UIImage imageNamed:@"postPlaceholder"] completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        if (!error) {

    }];


    return cell;
}

right now screen of tableview

Is there any solution for this? or can we use auto layout only for cell resizing?

Thanks in advance..


Solution

  • In an ideal case, I would normally expect the API to return all images with the same size or a size that can be configured through query string parameters like: /get_image/?width=400&height=400 etc.

    Anyway, the problem here is that, there is no way you can update the height of a cell once it was created and ready to be drawn onto screen (in other words, once it was returned from cellForRowAtIndexPath) unless you reload that cell or the entire table view manually. Luckily for us, sd_setImageWithURL works in an asynchronous manner which means you will have the opportunity to call tableView.reloadRowsAtIndexPath once the image has been fetched and stored.

    Reloading will cause heightForRowAtIndexPath to be called on the reloaded cell so we'll get the correct height this time.

    (Since table view cells are reusable objects, they don't store any information about the data they use in order to configure their UI. Thus, you need to store your images in your view controller, preferably inside an array.)

    @interface ViewController ()
    
    @property (nonatomic, strong) NSMutableArray *fetchedImages;
    @end
    
    @implementation ViewController
    ...
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
      UIImage *image = [self.fetchedImages objectAtIndex:indexPath.row];
      if (image) {
        return image.size.height + 1.0; // 1.0 for the separator.
      }
      else {
        return 50.0; // Default value..
      }
    }
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
      return self.fetchedImages.count;
    }
    

    With all that said, you can do something like the following in (tableView:cellForRowAtIndexPath:) method:

    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
      ...
    
      UIImage *image = [self.fetchedImages objectAtIndex:indexPath.row];
    
      if (image) {
        // If there is image don't bother fetching the image.
        cell.imageView.image = image;
      }
      else {
        NSURL *imageURL = [self.imageURLs objectAtIndex:indexPath.row];
        [cell.imageView sd_setImageWithURL:imageURL placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
        if (image) {
          [self.fetchedImages replaceObjectAtIndex:indexPath.row withObject:image];
          [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
        }
      }];
      return cell;
    }
    

    Here is the result I ended up:

    enter image description here

    You can download the test project and play around with it to have a better understanding about what I did above.