Как прокрутить до нижней части UITableView на iPhone, прежде чем появится представление - PullRequest
129 голосов
/ 05 мая 2010

У меня есть UITableView, который заполнен ячейками переменной высоты. Я бы хотел, чтобы таблица прокручивалась до самого дна, когда представление открывается.

В настоящее время у меня есть следующая функция

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[log count]-1 inSection:0];
[self.table scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO];

log - изменяемый массив, содержащий объекты, составляющие содержимое каждой ячейки.

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

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

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

Ответы [ 31 ]

8 голосов
/ 26 ноября 2014

Для Свифта:

if tableView.contentSize.height > tableView.frame.size.height {
    let offset = CGPoint(x: 0, y: tableView.contentSize.height - tableView.frame.size.height)
    tableView.setContentOffset(offset, animated: false)
}
5 голосов
/ 02 ноября 2016

Для Swift 3 (Xcode 8.1):

override func viewDidAppear(_ animated: Bool) {
    let numberOfSections = self.tableView.numberOfSections
    let numberOfRows = self.tableView.numberOfRows(inSection: numberOfSections-1)

    let indexPath = IndexPath(row: numberOfRows-1 , section: numberOfSections-1)
    self.tableView.scrollToRow(at: indexPath, at: UITableViewScrollPosition.middle, animated: true)
}
5 голосов
/ 24 марта 2011

Вы должны использовать UITableViewScrollPositionBottom вместо.

4 голосов
/ 18 августа 2015

Это, конечно, ошибка. Возможно, где-то в вашем коде вы используете table.estimatedRowHeight = value (например, 100). Замените это значение на наибольшее значение, которое, по вашему мнению, высота строки может получить , например, 500 .. Это должно решить проблему в сочетании со следующим кодом:

//auto scroll down example
let delay = 0.1 * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))

dispatch_after(time, dispatch_get_main_queue(), {
    self.table.scrollToRowAtIndexPath(NSIndexPath(forRow: self.Messages.count - 1, inSection: 0), atScrollPosition: UITableViewScrollPosition.Bottom, animated: false)
})
3 голосов
/ 19 февраля 2013

Используя вышеупомянутые решения, вы прокрутите страницу вниз (только если содержимое таблицы загружается первым):

//Scroll to bottom of table
CGSize tableSize = myTableView.contentSize;
[myTableView setContentOffset:CGPointMake(0, tableSize.height)];
3 голосов
/ 04 января 2017

In Swift 3.0

self.tableViewFeeds.setContentOffset(CGPoint(x: 0, y: CGFLOAT_MAX), animated: true)
3 голосов
/ 09 марта 2016

После долгих потрясений у меня сработало:

var viewHasAppeared = false

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    if !viewHasAppeared { goToBottom() }
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    viewHasAppeared = true
}

private func goToBottom() {
    guard data.count > 0 else { return }
    let indexPath = NSIndexPath(forRow: data.count - 1, inSection: 0)
    tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: false)
    tableView.layoutIfNeeded()
}

Ключ оказался , а не , обертывающим scrollToRowAtIndexPath внутри dispatch_async, как некоторые предлагали, но просто следуя за ним с вызовом layoutIfNeeded.

Насколько я понимаю, вызов метода прокрутки в потоке current гарантирует, что смещение прокрутки будет установлено немедленно, за до отображения представления. Когда я отправлял в основной поток, представление отображалось на мгновение, прежде чем прокрутка вступила в силу.

(Также NB вам нужен флаг viewHasAppeared, потому что вы не хотите goToBottom каждый раз, когда вызывается viewDidLayoutSubviews. Он вызывается, например, при изменении ориентации.)

2 голосов
/ 23 февраля 2017
func scrollToBottom() {

    let sections = self.chatTableView.numberOfSections

    if sections > 0 {

        let rows = self.chatTableView.numberOfRows(inSection: sections - 1)

        let last = IndexPath(row: rows - 1, section: sections - 1)

        DispatchQueue.main.async {

            self.chatTableView.scrollToRow(at: last, at: .bottom, animated: false)
        }
    }
}

Вы должны добавить

DispatchQueue.main.async {
            self.chatTableView.scrollToRow(at: last, at: .bottom, animated: false)
        }

, иначе он не будет прокручиваться вниз.

2 голосов
/ 06 октября 2016

Если вам необходимо загрузить данные асинхронно перед прокруткой вниз, вот возможное решение:

tableView.alpha = 0 // We want animation!
lastMessageShown = false // This is ivar

viewModel.fetch { [unowned self] result in
    self.tableView.reloadData()

    if !self.lastMessageShown {
        dispatch_async(dispatch_get_main_queue()) { [unowned self] in
            if self.rowCount > 0 {
                self.tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: self.rowCount, inSection: 0), atScrollPosition: .Bottom, animated: false)
            }

            UIView.animateWithDuration(0.1) {
                self.tableView.alpha = 1
                self.lastMessageShown = true // Do it once
            }
        }
    }
}
2 голосов
/ 07 мая 2013

Спасибо Джейкобу за ответ. действительно полезно, если кому-то интересно с monotouch c # версия

private void SetScrollPositionDown() {
    if (tblShoppingListItem.ContentSize.Height > tblShoppingListItem.Frame.Size.Height) {
        PointF offset = new PointF(0, tblShoppingListItem.ContentSize.Height - tblShoppingListItem.Frame.Size.Height);
        tblShoppingListItem.SetContentOffset(offset,true );
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...