UITableViewCell height resize when image is downloaded
You need to store downloaded image in the memory or on the disk, so next time when you will try to get image from this URL you will received from cache.
So if you do that than you will have to do something like this:
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
And you should return new cell's height in this method of table view data source:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
I would recomend you to use SDWebImage library instead of AFNetworking
because it can cache your images to memcache and disk for you and it is very easy to use. So if you decide to use it, your code of download images will be looking like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
...
[cell.imageView setImageWithURL:[NSURL URLWithString:@"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:@"placeholder.png"]
success:^(UIImage *image, BOOL cached) {
// save height of an image to some cache
[self.heightsCache setObject:[NSNumber numberWithFloat:imHeight]
forKey:urlKey];
[tableView beginUpdates];
[tableView reloadRowsAtIndexPaths:@[indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
failure:^(NSError *error) {... failure code here ...}];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
// try to get image height from your own heights cache
// if its is not there return default one
CGFloat height = [[self.heightsCache objectForKey:urlKeyFromModelsArrayForThisCell] floatValue];
...
return newHeight;
}
Comments
-
Jure about 2 years
I'm using
UIImageView+AFNetworking
category for async image loading. Everything works fine, but I've tried a couple of things and wasn't successful when resizing the cell's height according to the downloaded image. I want the image to fit to the width of the cell but resize in height, but I don't know how to accomplish that. I've tried reloading the row where the image was downloaded but that just causes thecellForRowAtIndexPath
to fire again and set everything again, etc. Almost a recursion.I'm calculating the new image size difference and storing that in
NSMutableArray
and then reloading the row in the success block in UIImageView'ssetImageWithURLRequest:placeholderImage:success:
.I get the correct height for a couple of rows in
heightForRowAtIndexPath
but then, the table starts acting weird and everything is overlaying, etc.Any ideas?
Thanks!
EDIT
I eventually used Ezeki's answer. I also wrote a post on the topic and made a sample app that uses this technique.
Check it out on here.
-
Jure over 11 yearsThanks, that's a great suggestion! Btw,
AFNetworking
handles caching as well. Anyway, I got it working but the tableview scrolling is now very jerky because of the reloading. Maybe I'll try preloading the images withSDWebImagePrecacher
. I have to find out a method of calculating the cell height because I have other subviews in the cell as well. -
Rajan Balana about 11 years@Jure Did you found the complete solution to the problem? I am going through same kind of problem. Can you help?
-
Surjit Sidhu over 10 yearswhere self.heightsCache property is declared ?
-
Ezeki over 10 yearsthat's just an NSMutableDictionary property, you can declare in in your ViewController.h file or in ViewController.m using category extension. Don't forget to initialize it in init or viewDidLoad. This mutable dictionary takes a url string as a key and NSNumber as a value.
-
Kosmetika about 10 years@Ezeki I tried to implement my tableview in this manner but as I see there are several minuses: 1. Memory - a lot of memory is needed for big lists while doing this calls
[tableView beginUpdates]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; [tableView endUpdates];
(I saw nearly 30mb for my list) 2. It's not so smooth -
Ezeki about 10 years@Kosmetika you can try reloading the table without row animation, maybe that would help. Anyway, please let me know the solution which really helps in your case
-
Mil0R3 about 10 years@Ezeki This solution make tableView always reloading data in a loop, I log the
self.heightsCache
intableView:heightForRowAtIndexPath
, the console is keep printing the log. -
Ezeki about 10 years@Geaka
tableView:heightForRowAtIndexPath:
is always called when new cell appears on the screen or when we reload the data. So If you scroll the tableView - yes, it would be always called, but if you don't touch it - it should call this method only when cell is reloading -
Joan Cardona about 8 yearsI keep getting this error: The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (0 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out). anybody knows how to fix it?
-
Jonny over 6 yearsLooks promising - did anyone write this for Swift yet?