UITableView вставлять строки без прокрутки - PullRequest
15 голосов
/ 03 мая 2011

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

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

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

[tableView beginUpdates];

[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationNone];

[tableView endUpdates];

NSUInteger iContentOffset = 200; //height of inserted rows

[tableView setContentOffset:CGPointMake(0, iContentOffset)];

Ответы [ 6 ]

17 голосов
/ 20 июля 2012

Если я правильно понимаю вашу миссию,

Я сделал это так:

if(self.tableView.contentOffset.y > ONE_OR_X_ROWS_HEIGHT_YOUDECIDE
{

    self.delayOffset = self.tableView.contentOffset;
    self.delayOffset = CGPointMake(self.delayOffset.x, self.delayOffset.y+ insertedRowCount * ONE_ROW_HEIGHT);

    [self.tableView reloadData];

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


}else
{
    [self.tableView insertRowsAtIndexPath:indexPathArray   WithRowAnimation:UITableViewRowAnimationTop];

}

С этим кодом, если пользователь находится в середине таблицы, а не вверху, uitableview перезагрузит новые строки без анимации и прокрутки. Если пользователь находится в верхней части таблицы, он увидит анимацию вставки строки.

Просто обратите внимание на код, я предполагаю, что высота строки равна, если нет, просто вычислите высоту всех новых строк, которые вы собираетесь вставить. Надеюсь, это поможет.

8 голосов
/ 04 мая 2011

Лучший способ найти желаемое поведение - совсем не анимировать вставку.Анимации вызывали хаотичность.

Вместо этого я звоню:

[tableView reloadData];

// set the content offset to the height of inserted rows 
// (2 rows * 44 points = 88 in this example)
[tableView setContentOffset:CGPointMake(0, 88)]; 

Это заставляет перезагрузку появляться одновременно с изменением смещения содержимого.

3 голосов
/ 29 октября 2016

Для дальнейших зрителей, ищущих решение Swift 3 + :

Вам необходимо сохранить текущее смещение UITableView, затем перезагрузить и затем установить смещение обратно на UITableView.

func reloadTableView(_ tableView: UITableView) {
    let contentOffset = tableView.contentOffset
    tableView.reloadData()
    tableView.layoutIfNeeded()
    tableView.setContentOffset(contentOffset, animated: false)
}

Вызывается по: reloadTableView(self.tableView)

1 голос
/ 05 апреля 2018

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

var indexpathsToReload: [IndexPath] = [] //this should contain the new indexPaths
var height: CGFloat = 0.0
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1) {
    UIView.performWithoutAnimation {

        self.tableview.reloadSections(NSIndexSet(index: 0) as IndexSet, with: .none) 
        self.tableview.layoutIfNeeded()
        indexpathsToReload.forEach({ (idx) in
            height += self.feed.rectForRow(at: idx).height
        })
        let afterContentOffset = self.tableview.contentOffset                             
        let newContentOffset = CGPoint(x: afterContentOffset.x, y: afterContentOffset.y + height)
        self.tableview.setContentOffset(newContentOffset, animated: false)
    }
}

CAVEAT (ПРЕДУПРЕЖДЕНИЕ) Этот метод не будет работать, если ваш просмотр таблицы не«полный», то есть в нем всего пара ячеек.В этом случае вам также необходимо увеличить contentSize таблицы вместе с contentOffset.Я обновлю этот ответ, как только угадаю его.

ОБЪЯСНЕНИЕ : По сути, нам нужно установить contentOffset tableView в положение, в котором он находился до перезагрузки,Для этого мы просто вычисляем общую высоту всех новых ячеек, которые были добавлены, используя предварительно заполненный массив indexPath (может быть подготовлен, когда вы получите новые данные и добавите их в источник данных), это indexPaths дляновые клетки.Затем мы используем общую высоту всех этих новых ячеек, используя rectForRow(at: indexPath), и устанавливаем ее как y положение contentOffset tableView после перезагрузки.DispatchQueue.main.asyncAfter не является необходимым, но я поместил его туда, потому что мне просто нужно дать столу некоторое время, чтобы вернуться в исходное положение, так как я делаю это по принципу «тянуть, чтобы обновить».Также обратите внимание, что в моем случае значение afterContentOffset.y всегда равно 0, поэтому вместо него можно было бы жестко указать 0.

1 голос
/ 27 июля 2016

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

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

-(void) loadMoreElements:(UIRefreshControl *) refreshControl {
  NSIndexPath *topIndexPath = [NSIndexPath indexPathForRow:0 inSection:0]
  id topElement = [myModel elementAtIndexPath:topIndexPath];

  // Somewhere here you'll need to tell your model to get more data
  [self.tableView reloadData];

  NSIndexPath *indexPath = [myModel indexPathForElement:topElement];

  [self.tableView scrollToRowAtIndexPath:indexPath 
                        atScrollPosition:UITableViewScrollPositionTop 
                                animated:NO];

  [refreshControl endRefreshing];
}
1 голос
/ 08 января 2015

Просто позвоните setContentOffset до endUpdates, это работает для меня.

[tableView setContentOffset:CGPointMake(0, iContentOffset)];
[tableView endUpdates];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...