Обновление UITableView без прокрутки

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

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

Каким будет лучший подход к его достижению?

Ответ 1

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

    // dataArray is your data Source object
    [dataArray insertObject:name atIndex:0];
    CGPoint contentOffset = self.tableView.contentOffset;
    contentOffset.y += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
    [self.tableView reloadData];
    [self.tableView setContentOffset:contentOffset];

Но для этого вам нужно определить метод - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath. Или же вы можете напрямую указать высоту строки tableview, если она постоянна.

Ответ 2

Для Swift 3 +:

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

Я создал эту функцию для этой цели:

func reload(tableView: UITableView) {

    let contentOffset = tableView.contentOffset
    tableView.reloadData()
    tableView.layoutIfNeeded()
    tableView.setContentOffset(contentOffset, animated: false)

}

Просто назовите его: reload(tableView: self.tableView)

Ответ 3

SWIFT 3

let contentOffset = self.tableView.contentOffset
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(contentOffset, animated: false)

Это ошибка iOS8 при использовании UITableViewAutomatic Dimension. Нам нужно сохранить смещение содержимого таблицы, перезагрузить таблицу, принудительно создать макет и вернуть contenOffset обратно.

CGPoint contentOffset = self.tableView.contentOffset;
[self.tableView reloadData];
[self.tableView layoutIfNeeded];
[self.tableView setContentOffset:contentOffset];

Ответ 4

Я делаю так:

messages.insertContentsOf(incomingMsgs.reverse(), at: 0)
table.reloadData()

// This is for the first load, first 20 messages, scroll to bottom
if (messages.count <= 20) {
      let indexToScroll = NSIndexPath(forRow: saferSelf.messages.count - 1, inSection: 0)
      table.scrollToRowAtIndexPath(indexToScroll, atScrollPosition: .Top , animated: false)
}
// This is to reload older messages on top of tableview
else {
      let indexToScroll = NSIndexPath(forRow: incomingMsgs.count, inSection: 0)
      table.scrollToRowAtIndexPath(indexToScroll, atScrollPosition: .Top , animated: false)
      // Remove the refreshControl.height + tableHeader.height from the offset so the content remain where it was before reload
      let theRightOffset = CGPointMake(0, table.contentOffset.y - refreshControl.frame.height - table.headeView.frame.height)
      table.setContentOffset(theRightOffset, animated: false)
}

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

var heightAtIndexPath = [NSIndexPath: CGFloat]()
func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return heightAtIndexPath[indexPath] ?? UITableViewAutomaticDimension
}
func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    heightAtIndexPath[indexPath] = cell.frame.height
}

Ответ 5

Просто установите estimatedRowHeight на максимально возможное значение.

 self.tableView.estimatedRowHeight = 1000
 self.tableView.estimatedSectionFooterHeight = 100.0
 self.tableView.estimatedSectionHeaderHeight = 500.0

Вот оно !!

Примечание: пожалуйста, не используйте значение FLT_MAX, DBL_MAX. Может быть, это сломает ваше приложение.

Ответ 6

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

let lastScrollOffset = tableView.contentOffset
tableView.beginUpdates()
tableView.reloadData()
tableView.endUpdates()
tableView.layer.removeAllAnimations()
tableView.setContentOffset(lastScrollOffset, animated: false)

Ответ 7

Использовать расширение

создайте UITableViewExtensions.swift и добавьте следующее:

extension UITableView {

    func reloadDataWithoutScroll() {
        let offset = contentOffset
        reloadData()
        layoutIfNeeded()
        setContentOffset(offset, animated: false)
    }
}

Ответ 8

Swift 4.2: простое решение

override func viewDidLoad() {
 super.viewDidLoad()

 self.tableView.estimatedRowHeight = 0
 self.tableView.estimatedSectionHeaderHeight = 0
 self.tableView.estimatedSectionFooterHeight = 0
}

//And then simply update(insert, reloadSections, delete etc) your tableView or reload

tableView.reloadData()

//or

UIView.performWithoutAnimation {

  tableView.beginUpdates()
  .....
  tableView.endUpdates()
}

Ответ 9

попробуйте заменить

reloadData с

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

но вы должны заботиться о no cells, если no cells, этот метод должен вызвать сбой.

Ответ 10

Если вы хотите перезагрузить, вы должны

self.tableView.reloadData()

self.tableView.layoutIfNeeded()

а также используйте UITableViewDelegate

func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return 'your maximum cell height'
}

и ваш tableView останется в предыдущей позиции прокрутки без прокрутки

Ответ 11

В iOS 12.x, используя Xcode 10.2.1, более простой вариант.

UIView.performWithoutAnimation { 
    let loc = tableView.contentOffset
    tableView.reloadRows(at: [indexPath], with: .none)
    tableView.contentOffset = loc
}

Это работает лучше, чем следующее; он трясет время от времени, когда ряд не виден полностью.

let contentOffset = self.tableView.contentOffset
self.tableView.reloadData()
self.tableView.layoutIfNeeded()
self.tableView.setContentOffset(contentOffset, animated: false)