Вызов reloadRowsAtIndexPaths удаляет tableView contentOffset - PullRequest
9 голосов
/ 24 мая 2011

Каждый раз, когда я вызываю

reloadRowsAtIndexPaths

Мой UITableView contentOffset удаляется, есть ли метод делегата, который я могу использовать, чтобы отследить обновление представления таблицы и снова установить смещение, чтобы оно оставалось на месте и не анимировалосьили просто запретить это делать?

Я устанавливаю contentOffest в viewDidLoad:

self.tableView.contentOffset = CGPointMake(0, 43);

Вот пример использования:

[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[params valueForKey:@"index"], nil] withRowAnimation:UITableViewRowAnimationFade];

, который удаляетcontentOffset и анимирует его в поле зрения, что мне не нужно.

Более конкретно, это происходит, когда перезагружаемая строка находится в indexPath.section 0 и indexPath.row 0, то есть в верхней строке.


Дополнительная информация

Я вызываю reloadRowsAtIndexPaths после асинхронного запроса на получение изображения с сервера.В основном это работает так:

  • Вызывается cellForRowAtIndexPath, который проверяет наличие файла большого пальца на диске, если файл отсутствует, вместо него загружается заполнитель и запускается асинхронный запрос.в фоновом потоке для извлечения изображения.
  • Когда загрузка изображения завершится, я вызываю reloadRowsAtIndexPaths для правильной ячейки, так что вместо изображения-заполнителя появляется правильное изображение.
  • Количество ячеек может отличаться, так как запрос вызывается внутри cellForRowAtIndexPath, поэтому изображения загружаются при загрузке ячеек

Проверка файла cellForRowAtIndexPath

paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_small.gif",[[listItems objectAtIndex:indexPath.row] valueForKey:@"slug"]]];

    if([[NSFileManager defaultManager] fileExistsAtPath:path]){

        listCell.imageView.image = [UIImage imageWithData:[NSData dataWithContentsOfFile:path]];

    } else {

        listCell.imageView.image = [UIImage imageNamed:@"small_placeholder.gif"];

        NSMutableDictionary *params = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[[[listItems objectAtIndex:indexPath.row] valueForKey:@"image"] valueForKey:@"small"],@"image",[NSString stringWithFormat:@"%@_small.gif",[[listItems objectAtIndex:indexPath.row] valueForKey:@"slug"]], @"name",indexPath,@"index",@"listFileComplete",@"notification",nil];

        [NSThread detachNewThreadSelector:@selector(loadImages:) toTarget:self withObject:params];

        [params release];

    }

Уведомление о загрузке файла:

-(void)fileComplete:(NSNotification *)notification {

    [self performSelectorOnMainThread:@selector(reloadMainThread:) withObject:[notification userInfo] waitUntilDone:NO];
}

Перезагрузка ячейки (у меня жестко закодированные разделы из-за ошибки, при которой странные номера разделов пропускаются очень редко, вызывая сбой:

-(void)reloadMainThread:(NSDictionary *)params {

    NSIndexPath *index;

    switch ([[params valueForKey:@"index"] section]) {
        case 0:
            index = [NSIndexPath indexPathForRow:[[params valueForKey:@"index"] row] inSection:0];
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:[params valueForKey:@"index"], nil] withRowAnimation:UITableViewRowAnimationNone];
            break;
        default:
            index = [NSIndexPath indexPathForRow:[[params valueForKey:@"index"] row] inSection:2];
            [self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObjects:index,nil] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }

}

Ответы [ 5 ]

3 голосов
/ 19 июня 2016

Звучит так, будто вы столкнулись с этой проблемой из-за неверно оцененных высот строк. Поскольку (по какой-то таинственной причине) табличное представление определяет новое смещение после перезагрузки некоторых ячеек, используя оценочную высоту строки , вы хотите убедиться, что tableView:estimatedHeightForRowAtIndexPath возвращает правильные данные для ячеек, которые уже были отрисованы. Для этого вы можете кэшировать видимую высоту строки в словаре:

override func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    heightForIndexPath[indexPath] = cell.frame.height
}

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

override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return heightForIndexPath[indexPath] ?? averageRowHeight
}

(ОГРОМНОЕ спасибо eyuelt за понимание того, что расчетная высота строки используется для определения нового смещения.)

3 голосов
/ 24 мая 2011

РЕДАКТИРОВАТЬ: Мой первоначальный ответ, возможно, не был сосредоточен на основной проблеме

Вы меняете количество строк перед вызовом на reloadRows...? reloadRows... специально для анимации изменения значения, поэтому ваш код должен выглядеть примерно так:

UICell *cell = [self cellForRowAtIndexPath:indexPath];
cell.label.text = @"Something new";
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]];

Это более или менее то, на что вы похожи, но табличное представление забывает, где оно находится?


Предыдущее обсуждение

Вы не звоните -beginUpdates и -endUpdates вокруг перезагрузки. Вы звоните -beginUpdates и -endUpdates в связи с вашими соответствующими изменениями данных поддержки, во время которых вам следует звонить -insertRowsAtIndexPaths:withRowAnimation: и его родственникам. Если вы вызываете подпрограммы обновления, вам не нужно вызывать подпрограммы перезагрузки. Перезагрузка в середине обновления - неопределенное поведение.

См. Пакетная вставка, удаление и перезагрузка строк и разделов для получения подробных сведений об использовании -beginUpdates.

0 голосов
/ 06 сентября 2016

Я использую это:

-(void)keepTableviewContentOffSetCell:(cellClass *)cell{
    CGRect rect = cell.frame;
    self.tableView.estimatedRowHeight = rect.size.height ;
}

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

0 голосов
/ 17 апреля 2016

Замените

[_tableView reloadData];

на

[_tableView  reloadRowsAtIndexPaths:...withRowAnimation:...];

, и это будет хорошо.

0 голосов
/ 24 мая 2011

Вы пробовали следующее:

CGPoint offset = [self.tableView contentOffset];
CGSize size = [self.tableView contentSize];

CGFloat percentScrolled = offset.y / size.height;

// call reloadRowsAtIndexPaths, inserts, deletes etc.
// ...

CGSize newSize = [self.tableView contentSize];
CGSize newOffset = CGPointMake(0, newSize.height * percentScrolled);

[self.tableView setContentOffset:newOffset animated:NO];

Это кажется слишком тривиальным, не уверен, что это сработает, но стоит попробовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...