Подтвердить что ты не робот

Как сохранить UITableView contentoffset после вызова -reloadData

CGPoint offset = [_table contentOffset];
[_table reloadData];
[_table setContentOffset:offset animated:NO];    //unuseful

//    __block UITableView *tableBlock = _table;
//    [self performBlock:^(id sender) {
//        [tableBlock setContentOffset:offset];
//    } afterDelay:2];

Я знаю, не знаю ни одного метода делегата, который reloadData после reloadData. И использование afterDelay:2 которое является своего рода хаком, может быть слишком коротким или слишком длинным, так как я могу его реализовать?

4b9b3361

Ответ 1

Недавно я работал с reloadData - reloadData не менял contentOffset или прокручивал представление таблицы. Фактически он остается прежним, если смещение меньше, чем новый объем данных.

Ответ 2

У меня были проблемы с этим, потому что я возился с размером ячейки в моем методе cellForRowAtIndexPath. Я заметил, что информация о калибровке отключена после выполнения reloadData, поэтому я понял, что мне нужно заставить ее компоновку непосредственно перед настройкой смещения содержимого.

CGPoint offset = tableView.contentOffset;
[tableView.messageTable reloadData];
[tableView layoutIfNeeded]; // Force layout so things are updated before resetting the contentOffset.
[tableView setContentOffset:offset];

Ответ 3

Вызов reloadData в таблицеView не изменяет смещение содержимого. Однако, если вы используете UITableViewAutomaticDimension, который был введен в iOS 8, у вас может возникнуть проблема.

При использовании UITableViewAutomaticDimension необходимо написать метод делегата tableView: estimatedHeightForRowAtIndexPath: и вернуть UITableViewAutomaticDimension вместе с tableView: heightForRowAtIndexPath:, который также возвращает то же самое.

Для меня у меня были проблемы с iOS 8 при использовании этого. Это связано с тем, что метод estimatedHeightForRowAtIndexPath: возвращал неточные значения, хотя я использовал UITableViewAutomaticDimension. Это была проблема с iOS 8, поскольку никаких проблем с устройствами iOS 9 не было.

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

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSNumber *key = @(indexPath.row);
    NSNumber *height = @(cell.frame.size.height);

    [self.cellHeightsDictionary setObject:height forKey:key];
}

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSNumber *key = @(indexPath.row);
    NSNumber *height = [self.cellHeightsDictionary objectForKey:key];

    if (height)
    {
        return height.doubleValue;
    }

    return UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewAutomaticDimension;
}

Проверка наличия высоты для загрузки первой страницы.

Ответ 4

По умолчанию reloadData сохраняет contentOffset. Тем не менее, он может быть обновлен, если у вас есть неверные оценочные значения RowHeight.

Ответ 5

Swift 4 варианта ответа @Skywalker:

fileprivate var heightDictionary: [Int : CGFloat] = [:]

override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
    heightDictionary[indexPath.row] = cell.frame.size.height
}

override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    let height = heightDictionary[indexPath.row]
    return height ?? UITableViewAutomaticDimension
}

Другое решение (полученное из MessageKit):

Этот метод следует вызывать вместо reloadData. Это может соответствовать конкретным случаям.

public func reloadDataAndKeepOffset() {
    // stop scrolling
    setContentOffset(contentOffset, animated: false)

    // calculate the offset and reloadData
    let beforeContentSize = contentSize
    reloadData()
    layoutIfNeeded()
    let afterContentSize = contentSize

    // reset the contentOffset after data is updated
    let newOffset = CGPoint(
        x: contentOffset.x + (afterContentSize.width - beforeContentSize.width),
        y: contentOffset.y + (afterContentSize.height - beforeContentSize.height))
    setContentOffset(newOffset, animated: false)
}

Ответ 6

В моем случае снимите отметку высоты строки автоматически и оцените автоматическую задачу

fix reload problem

Ответ 7

Если вы вставляете данные в начало массива dataSource, вам нужно изменить contentOffset следующим образом: Swift 3 +

func prepareReloadData() {
    let previousContentHeight = tableView.contentSize.height
    let previousContentOffset = tableView.contentOffset.y
    tableView.reloadData()
    let currentContentOffset = tableView.contentSize.height - previousContentHeight + previousContentOffset
    tableView.contentOffset = CGPoint(x: 0, y: currentContentOffset)
}

Ответ 8

У меня была такая же проблема, однако ни один из предложенных здесь ответов не работал. Вот как я решил это. Подкласс UITableView и переопределить метод layoutSubviews следующим образом:

override func layoutSubviews() {
    let offset = contentOffset
    super.layoutSubviews()
    contentOffset = offset
}

Ответ 9

Если вы реализуете estimatedHeightForRowAtIndexPath метод и ваша оценка не является правильным, вы возможно попасть в эту ситуацию.

Чтобы решить эту проблему, вы можете вернуть большую высоту, которая больше, чем каждая высота ячейки в вашем TableView, например:

- (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { 
    return 800.f; // if 800 is bigger than every possible value of your cell height.
}

Ответ 10

Ответ @Skywalker показал наилучшее обходное решение для оценки высоты клеток. Но иногда проблема лишает в другом месте.
Иногда проблема лишена в contentInsets табличного представления. Если вы делаете данные перезагрузки, а таблицаView не видна на экране, вы можете столкнуться с неправильным смещением после появления на экране табличного представления.
Это происходит потому, что UIViewController может контролировать вставки, если его scrollView, когда scrollView появляется, позволяет лгать scrollView под прозрачной навигационной панелью и статусом.
Я столкнулся с таким поведением в iOS 9.1

Ответ 11

Это сработало для меня (Swift 3)

self.table.reloadData()
self.table.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)

Ответ 12

Это работает 100%

change the tableView.reloadData() 

в

tableView.reloadRows(at: tableView!.indexPathsForVisibleRows!, with: .none)

Ответ 13

Для этого отлично работает

[tView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]
             atScrollPosition:UITableViewScrollPositionTop
                     animated:NO];