Изменение размера высоты UITableViewCell при загрузке изображения

Я использую категорию UIImageView+AFNetworking для асинхронной загрузки изображений. Все работает нормально, но я попробовал пару вещей и не смог изменить размер ячейки в соответствии с загруженным изображением. Я хочу, чтобы изображение соответствовало ширине ячейки, но изменялось по высоте, но я не знаю, как это сделать. Я попытался перезагрузить строку, в которую было загружено изображение, но это просто заставляет cellForRowAtIndexPath снова срабатывать и снова устанавливать все и т. Д. Почти рекурсия.

Я вычисляю разницу в размере нового изображения и сохраняю ее в NSMutableArray, а затем перезагружаю строку в блоке успеха в setImageWithURLRequest:placeholderImage:success: UIImageView.

Я получаю правильную высоту для пары строк в heightForRowAtIndexPath, но затем таблица начинает вести себя странно, все накладывается и т. д.

Любые идеи?

Спасибо!

ИЗМЕНИТЬ

В конце концов я использовал ответ Эзеки. Я также написал сообщение на эту тему и сделал пример приложения, использующего эту технику.

Проверьте это на здесь.


person Jure    schedule 27.10.2012    source источник


Ответы (2)


Вам нужно сохранить загруженное изображение в память или на диск, чтобы в следующий раз, когда вы попытаетесь получить изображение с этого URL, вы получите его из кеша.

Итак, если вы это сделаете, вам придется сделать что-то вроде этого:

[tableView beginUpdates];

[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

[tableView endUpdates];

И вы должны вернуть новую высоту ячейки в этом методе источника данных табличного представления:

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

Я бы порекомендовал вам использовать библиотеку SDWebImage вместо AFNetworking, потому что она может кэшировать ваши изображения в кэш памяти и на диск для вас, и это очень просто использовать. Поэтому, если вы решите его использовать, ваш код загрузки изображений будет выглядеть так:

- (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;
}
person Ezeki    schedule 27.10.2012
comment
Спасибо, это отличное предложение! Кстати, AFNetworking также обрабатывает кеширование. Во всяком случае, у меня все заработало, но прокрутка таблицы теперь очень прерывистая из-за перезагрузки. Может быть, я попробую предварительно загрузить изображения с помощью SDWebImagePrecacher. Мне нужно найти метод вычисления высоты ячейки, потому что у меня есть и другие подвиды в ячейке. - person Jure; 28.10.2012
comment
@Jure Вы нашли полное решение проблемы? Я переживаю такую ​​же проблему. Вы можете помочь? - person Rajan Balana; 22.05.2013
comment
где объявлено свойство self.heightsCache? - person Surjit Sidhu; 01.11.2013
comment
это всего лишь свойство NSMutableDictionary, которое вы можете объявить в своем файле ViewController.h или в ViewController.m, используя расширение категории. Не забудьте инициализировать его в init или viewDidLoad. Этот изменяемый словарь принимает строку URL-адреса в качестве ключа и NSNumber в качестве значения. - person Ezeki; 01.11.2013
comment
@Ezeki Я пытался реализовать свое табличное представление таким образом, но, как я вижу, есть несколько минусов: 1. Память - для больших списков требуется много памяти, при этом вызывается [tableView beginUpdates]; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; [tableView endUpdates]; (я видел около 30 МБ для моего списка) 2. Это не так гладко - person Kosmetika; 03.05.2014
comment
@Kosmetika, вы можете попробовать перезагрузить таблицу без анимации строк, может быть, это поможет. В любом случае, пожалуйста, дайте мне знать решение, которое действительно помогает в вашем случае. - person Ezeki; 05.05.2014
comment
@Ezeki Это решение заставляет tableView всегда перезагружать данные в цикле, я регистрирую self.heightsCache в tableView:heightForRowAtIndexPath, консоль продолжает печатать журнал. - person Mil0R3; 09.05.2014
comment
@Geaka tableView:heightForRowAtIndexPath: всегда вызывается, когда на экране появляется новая ячейка или когда мы перезагружаем данные. Итак, если вы прокручиваете tableView - да, он всегда будет вызываться, но если вы его не трогаете - он должен вызывать этот метод только при перезагрузке ячейки. - person Ezeki; 09.05.2014
comment
Я продолжаю получать эту ошибку: количество строк, содержащихся в существующем разделе после обновления (1), должно быть равно количеству строк, содержащихся в этом разделе до обновления (0), плюс или минус количество вставленных или удаленных строк из этого раздела (0 добавлено, 0 удалено) и плюс или минус количество строк, перемещенных в этот раздел или из него (0 добавлено, 0 удалено). кто-нибудь знает, как это исправить? - person Joan Cardona; 23.04.2016
comment
Выглядит многообещающе — кто-нибудь уже написал это для Swift? - person Jonny; 25.01.2018

Для меня это работает:

Вы проверяете, доступно ли изображение кеша или нет, если оно доступно, оно устанавливается на изображение, а если нет, оно загружается, а затем сбрасывается макет таблицы, вызывая пути перезагрузки индекса.

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *broadcastTableCellIdentifier = @"BlockbusterTableViewCell";

BlockbusterTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:broadcastTableCellIdentifier];

if (cell == nil) {
    cell = [[BlockbusterTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:broadcastTableCellIdentifier];
}

[self configureCell:cell atIndexPath:indexPath];
return cell;
}



-(void)configureCell:(BlockbusterTableViewCell*)cell atIndexPath:(NSIndexPath*)indexPath{
    SportData *data = [self.webShared.arrSportsData objectAtIndex:self.selectedEvent];
    BroadcastData *broadcastData = [data.broadcastData objectAtIndex:indexPath.row];

NSURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:broadcastData.image]];

AFImageDownloader *downloader = [UIImageView sharedImageDownloader];
id <AFImageRequestCache> imageCache = downloader.imageCache;

UIImage *cacheimage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
    if (cell.imgBroadcast.image != cacheimage) {
        [cell.imgBroadcast setImageWithURLRequest:urlRequest placeholderImage:[UIImage imageNamed:@"placeholder_smaller"] success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) {

                cell.imgBroadcast.image = image;
                [self.tableViewBroadcast beginUpdates];

                [self.tableViewBroadcast reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];

                [self.tableViewBroadcast endUpdates];

        } failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {

        }];

    }
    else{
        cell.imgBroadcast.image =cacheimage;
    }

    cell.lblTitle.text = broadcastData.title;
    cell.lblText.text = broadcastData.text;
    cell.lblEventDateTime.text = [self eventTime:broadcastData.eventTime];
}
person Dhara Ahuja    schedule 30.11.2016