0

How to properly calculate the height of the UITableViewCell when this height is based on the table cell width.

I'm trying to put code in heightForRowAtIndexPath method but trying to get reference for the cell in this method is impossible because it generate infinite loop. In my cell I'm loading the image and try to display it on all cell area. The image is scaled with View mode AspectFit so the width of the image fits ok in the cell but I don't know how to calculate height so all image will be visible. Using only image height is not good option because this image is scaled and fitted to the cell so its real height is much smaller after scaling.

I'm using this code to calculate the height and I don't know how to implement it correctly so this method return proper height of the image after scaling and fit to the cell content.

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
NSDictionary *item = self.items[indexPath.row];
UIImage *image = (UIImage *)item[COUPON_IMAGE_BINARY];

if (image) {
    // here the image is loaded so we can calculate somehow the
    // height of the cell after the image is scaled.
    // The image is always scaled to the width of the cell.
    // How can I get here the cell width?

    return image.size.height; // this only works for images that doesn't need any scaling
}
return 50;
}

Also here is my method cellForRowAtIndex:

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

UIImageTableViewCell *cell = (UIImageTableViewCell *)[self.tableView dequeueReusableCellWithIdentifier:itemCellID
                                                             forIndexPath:indexPath];
if (cell.imageDownloadTask) {
    [cell.imageDownloadTask cancel];
}

NSMutableDictionary *item = self.items[indexPath.row];
if (item[COUPON_IMAGE_BINARY]) {
    cell.customImageView.image = (UIImage *)item[COUPON_IMAGE_BINARY];
    return cell;
}
// image is not loaded yet
NSURL *imageURL = [NSURL URLWithString:item[COUPON_IMAGE_URL]];
if (imageURL) {
    cell.imageDownloadTask = [self.session dataTaskWithURL:imageURL
                                         completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                             if (error) {
                                                 NSLog(@"ERROR: %@", error);
                                             } else {
                                                 NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                                                 if (httpResponse.statusCode == 200) {
                                                     UIImage *image = [UIImage imageWithData:data];
                                                     item[COUPON_IMAGE_BINARY] = image; // image is ready to use
                                                     dispatch_async(dispatch_get_main_queue(), ^{
                                                         [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                                                                               withRowAnimation:UITableViewRowAnimationNone];
                                                     });
                                                 } else {
                                                     NSLog(@"Couldn't load image at URL: %@", imageURL);
                                                     NSLog(@"HTTP %d", httpResponse.statusCode);
                                                 }
                                             }
                                         }];
    [cell.imageDownloadTask resume];
} 
return cell;
}

I was looking for solution and read almost 10 of them but solutions provided didn't work for me. Can somebody put more light on this topic? I can't make those images returned from server scaled because backend don't support such features. What I would like to do is to scale the image in device and display it as wide as cell is with original proportions so cell height is dependent on the cell width.

Marcin Kapusta
  • 5,076
  • 3
  • 38
  • 55

1 Answers1

4

Just maintain the aspect ratio

CGFloat cellHeight = (image.size.height / image.size.width) * tableView.bounds.size.width;

Make sure to limit height to a certain point

cellHeight = MIN(cellHeight, MAX_HEIGHT);
kean
  • 1,561
  • 14
  • 22
  • Thank You. It works! But what if my cell has accessory Detail Disclosure. Then the cell is not as wide as the tableView.bounds and the width area of the cell.contentView is smaller than tableView.bounds.size.width? The real challenge for me is to calculate proper cell width that is needed to calculate cell height. If I set Accessory to None then it works great. – Marcin Kapusta Feb 25 '15 at 15:14
  • You can either hard code a value or create a single prototype cell, store it in a controller's property and use it for calculations. There is a [similar question](http://stackoverflow.com/questions/902096/uitableviewcells-contentviews-width-with-a-given-accessory-type) – kean Feb 25 '15 at 15:25
  • Btw, you are not decompressing images in a background. Image decompression is a heavy operation (especially for JPEG), and right now it happens on the main thread. There are frameworks that handle everything for you like [SDWebImage](https://github.com/rs/SDWebImage) and recent [DFImageManager](https://github.com/kean/DFImageManager) that I just released. – kean Feb 25 '15 at 15:30
  • Great idea with one prototype cell. I would also like to say Thank You for Your knowledge sharing and for Your note about decompression. I will try use DFImageManager. – Marcin Kapusta Feb 26 '15 at 10:10
  • Thank You! If you'll have any questions about DFImageManager just create a question with 'dfimagemanager' tag :) – kean Feb 26 '15 at 10:39