UITableView - прокрутите вверх


393

В моем табличном представлении я должен прокрутить к вершине. Но я не могу гарантировать, что первым объектом будет секция 0, строка 0. Может быть, мое табличное представление начнется с секции № 5.

Поэтому я получаю исключение, когда звоню:

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

Есть ли другой способ прокрутки до верхней части таблицы?

Ответы:


857

UITableView является подклассом UIScrollView, поэтому вы также можете использовать:

[mainTableView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];

Или

[mainTableView setContentOffset:CGPointZero animated:YES];

И в Свифте:

mainTableView.setContentOffset(CGPointZero, animated:true)

И в Swift 3 и выше:

mainTableView.setContentOffset(.zero, animated: true)

9
Сначала я попробовал это с CGRectZero, который эквивалентен CGRectMake (0, 0, 0, 0). Это не работает, но, как ни странно, выше. Я предполагаю, что это нуждается в положительной ширине и высоте. Спасибо.
Келлер

5
Обратите внимание, вам понадобится анимация: НЕТ, если вы запустите это в scrollToRowAtIndexPath: чтобы таблица начиналась в правильном положении. Надеюсь, поможет!
Толстяк

3
@ hasan83 CGRectMake (0, 0, 0, 0) или CGRectZero не является видимым прямоугольником. Я также сказал бы, что [mainTableView setContentOffset: CGPointZero animated: YES]; это красивее выражение.
Catlan

8
кто-нибудь заметил, что в iOS11 это все сломано и не прокручивается правильно в некоторых случаях?
Питер Лапису

11
@PeterLapisu, self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)кажется, работает в iOS 11
Джордан С

246

Примечание . Этот ответ не подходит для iOS 11 и более поздних версий.

я предпочитаю

[mainTableView setContentOffset:CGPointZero animated:YES];

Если у вас есть верхняя вставка в табличном представлении, вы должны вычесть это:

[mainTableView setContentOffset:CGPointMake(0.0f, -mainTableView.contentInset.top) animated:YES];

12
Помидор, помидор. Хм ... Это не очень ясно в письменной форме.
FreeAsInBeer

14
Это лучший способ использовать, когда у вас есть представления верхнего или нижнего колонтитула таблицы и вы хотите, чтобы они тоже были включены.
Мафоня

6
Это действительно чистый код, но он не работает, когда у вас tableViewненулевой contentInsetсверху. Например: tableView.contentInset = UIEdgeInsetsMake(5.0f, 0.0f, 250.0f, 0.0f);. Если это так, в вашем коде tableViewпрокручивается до (0.0f, 5.0f).
Толгаморф

25
Решение моего предыдущего комментария:[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
tolgamorf

3
На iOS 11 вы должны рассмотреть возможность использования -scrollView.adjustedContentInset.topвместо.
Мариан Черны

79

Возможные действия:

1

func scrollToFirstRow() {
    let indexPath = NSIndexPath(forRow: 0, inSection: 0)
    self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
}

2

func scrollToLastRow() {
    let indexPath = NSIndexPath(forRow: objects.count - 1, inSection: 0)
    self.tableView.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Bottom, animated: true)
}

3

func scrollToSelectedRow() {
    let selectedRows = self.tableView.indexPathsForSelectedRows
    if let selectedRow = selectedRows?[0] as? NSIndexPath {
        self.tableView.scrollToRowAtIndexPath(selectedRow, atScrollPosition: .Middle, animated: true)
    }
}

4

func scrollToHeader() {
    self.tableView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
}

5

func scrollToTop(){
    self.tableView.setContentOffset(CGPointMake(0,  UIApplication.sharedApplication().statusBarFrame.height ), animated: true)
}

Отключить Scroll To Top:

func disableScrollsToTopPropertyOnAllSubviewsOf(view: UIView) {
    for subview in view.subviews {
        if let scrollView = subview as? UIScrollView {
            (scrollView as UIScrollView).scrollsToTop = false
        }
        self.disableScrollsToTopPropertyOnAllSubviewsOf(subview as UIView)
    }
}

Изменить и использовать его согласно требованию.

Swift 4

  func scrollToFirstRow() {
    let indexPath = IndexPath(row: 0, section: 0)
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
  }

Это идеальное решение - scrollToFirstRow
Mehul

Отличное резюме. Когда у вас есть заголовки разделов, вам придется использовать option4 scrollToHeader.
Винсент

Есть ли способ прокрутить вверх до панели поиска, которая находится над табличным представлением?
Тайлер Ратт

27

Лучше не использовать NSIndexPath (пустая таблица) и не предполагать, что верхняя точка - это CGPointZero (вставки содержимого), вот что я использую -

[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];

Надеюсь это поможет.


Больше не действует с iOS 11.
rmaddy

21

Свифт 4 :

Это работает очень хорошо:

//self.tableView.reloadData() if you want to use this line remember to put it before 
let indexPath = IndexPath(row: 0, section: 0)
self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)

3
Нет, если у вас есть tableHeaderView в вашем tableView и он встроен (прокручивается вместе с содержимым)
finneycanhelp

1
У меня есть и обычный и UITableViewStyleGrouped(заголовки прокручивается с содержимым), и этот код работает. Убедитесь, что вы находитесь в главном потоке, и вы запускаете этот код после появления представления ( viewDidAppear). Если у вас все еще есть проблемы, попробуйте поместить код внутри этого:DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: { // the code }
Алессандро Орнано

1
Спасибо. Это приведет вас к первой камере. Однако он не показывает заголовок табличного представления.
finneycanhelp

Это не удастся, если tableView по какой-то причине пуст (нет ячейки в секции 0 в строке 0)
Максим Скрябин

17

Я столкнулся с проблемой вызова некоторых методов на пустом месте tableView. Вот еще один вариант для Swift 4, который обрабатывает пустые просмотры таблиц.

extension UITableView {
  func hasRowAtIndexPath(indexPath: IndexPath) -> Bool {
    return indexPath.section < self.numberOfSections && indexPath.row < self.numberOfRows(inSection: indexPath.section)
  }

  func scrollToTop(animated: Bool) {
    let indexPath = IndexPath(row: 0, section: 0)
    if self.hasRowAtIndexPath(indexPath: indexPath) {
      self.scrollToRow(at: indexPath, at: .top, animated: animated)
    }
  }
}

Применение:

// from yourViewController or yourTableViewController
tableView.scrollToTop(animated: true)//or false

Это не учитывает заголовок таблицы или заголовок раздела.
rmaddy

16

НЕ ИСПОЛЬЗУЙТЕ

 tableView.setContentOffset(.zero, animated: true)

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

ВМЕСТО ИСПОЛЬЗОВАНИЯ

 tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)

1
Идеальное решение.
Baby Groot

Именно то, что я искал, спасибо.
Симон

Ни одно из этих решений не является действительным. Первый не работает под iOS 11 или новее. Второе не работает, если в табличном представлении есть заголовок таблицы или в первом разделе есть заголовок раздела, если вы действительно не хотите, чтобы первая строка находилась сверху, и вам не нужно показывать какие-либо заголовки.
rmaddy

@rmaddy какое лучшее решение?
ScottyBlades

15

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

if (@available(iOS 11.0, *)) {
    [tableView setContentOffset:CGPointMake(0, -tableView.adjustedContentInset.top) animated:YES];
} else {
    [tableView setContentOffset:CGPointMake(0, -tableView.contentInset.top) animated:YES];
}

Swift:

if #available(iOS 11.0, *) {
    tableView.setContentOffset(CGPoint(x: 0, y: -tableView.adjustedContentInset.top), animated: true)
} else {
    tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: true)
}

12

Для таблиц, которые имеют contentInset, установка смещения содержимого наCGPointZero не будет работать. Он будет прокручиваться до верхней части содержимого, а не до верхней части таблицы.

Принятие содержимого во внимание производит это вместо этого:

[tableView setContentOffset:CGPointMake(0, -tableView.contentInset.top) animated:NO];

1
Спасибо, я продолжал устанавливать его в CGPointZero и не мог понять, почему это происходит.
Джонрехд

Больше не действует с iOS 11.
rmaddy

10

Этот код позволяет прокручивать определенный раздел вверх

CGRect cellRect = [tableinstance rectForSection:section];
CGPoint origin = [tableinstacne convertPoint:cellRect.origin 
                                    fromView:<tableistance>];
[tableinstance setContentOffset:CGPointMake(0, origin.y)];

Это был самый простой код, и он работал нормально. Я на самом деле поставил CGPointMake (0.0f, 0.0f). Ура!
Фелипе

Этот код очень полезен для того, чтобы сделать раздел прокручиваемым вверху
srinivas n


8

Свифт 3

tableView.setContentOffset(CGPoint.zero, animated: true)

если tableView.setContentOffset не работает

Использование:

tableView.beginUpdates()
tableView.setContentOffset(CGPoint.zero, animated: true)
tableView.endUpdates()

1
Это не действительно для iOS 11 или более поздней версии.
rmaddy

7

Так как мой tableViewполон всевозможных вставок, это было единственное, что сработало хорошо:

Свифт 3

if tableView.numberOfSections > 0 && tableView.numberOfRows(inSection: 0) > 0 {
  tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
}

Swift 2

if tableView.numberOfSections > 0 && tableView.numberOfRowsInSection(0) > 0 {
  tableView.scrollToRowAtIndexPath(NSIndexPath(forRow: 0, inSection: 0), atScrollPosition: .Top, animated: true)
}

это было более полезным для меня
Тейзератул

отличный ответ, ценю это
Джереми Бадер

7

В дополнение к тому, что уже было сказано, вы можете создать расширение (Swift) или категорию (Objective C), чтобы упростить это в будущем:

Swift:

extension UITableView {
    func scrollToTop(animated: Bool) {
        setContentOffset(CGPointZero, animated: animated)
    }
}

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

tableView.scrollToTop(animated: true)

2
Больше не действует с iOS 11.
rmaddy

6

Я предпочитаю следующее, так как оно учитывает вкладку. Если вставка отсутствует, она все равно будет прокручиваться вверх, так как вставка будет 0.

tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: true)

Больше не действует с iOS 11.
rmaddy

5

Свифт:

если у вас нет заголовка tableView:

tableView.setContentOffset(CGPointMake(0,  UIApplication.sharedApplication().statusBarFrame.height ), animated: true)

если так :

tableView.setContentOffset(CGPointMake(0, -tableViewheader.frame.height   + UIApplication.sharedApplication().statusBarFrame.height ), animated: true)

5

Swift 5, iOS 13

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

tableView.scrollToRow(at: IndexPath(row: someArray.count - 1, section: 0), at: .bottom, animated: true)

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


Вы также должны проверить, есть ли раздел
Onur Tuna

4

Вот что я использую для корректной работы на iOS 11:

extension UIScrollView {
    func scrollToTop(animated: Bool) {
        var offset = contentOffset
        if #available(iOS 11, *) {
            offset.y = -adjustedContentInset.top
        } else {
            offset.y = -contentInset.top
        }
        setContentOffset(offset, animated: animated)
    }
}

4

В Swift 5, спасибо @ Адриан ответ много

extension UITableView{

    func hasRowAtIndexPath(indexPath: IndexPath) -> Bool {
        return indexPath.section < numberOfSections && indexPath.row < numberOfRows(inSection: indexPath.section)
    }

    func scrollToTop(_ animated: Bool = false) {
        let indexPath = IndexPath(row: 0, section: 0)
        if hasRowAtIndexPath(indexPath: indexPath) {
            scrollToRow(at: indexPath, at: .top, animated: animated)
        }
    }

}

Применение:

tableView.scrollToTop()

2
1. Это также действует в Swift 4. 2. Это не работает, если есть заголовок таблицы или заголовок раздела.
rmaddy

3

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

tableView.scrollToRow(at: NSIndexPath.init(row: 0, section: 0) as IndexPath, at: .top, animated: true)

2
Это не будет работать, если есть заголовок таблицы или заголовок раздела.
rmaddy

3

Это был единственный фрагмент кода, который работал для меня

Свифт 4:

    tableView.scrollRectToVisible(CGRect(x: 0, y: 0, width: 1, height: 1), animated: true)
    tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
    tableView.setContentOffset(CGPoint(x: 0, y: -70), animated: true)

PS 70 - высота моего заголовка и ячейки табличного представления


Это далеко от правильного способа прокрутки к вершине. Нет смысла использовать три отдельные строки только для установки смещения содержимого. Требуется только последняя строка, но жесткое кодирование определенного смещения не является правильным решением.
rmaddy

2
func scrollToTop() {
        NSIndexPath *topItem = [NSIndexPath indexPathForItem:0 inSection:0];
        [tableView scrollToRowAtIndexPath:topItem atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

вызывайте эту функцию везде, где вы хотите, чтобы UITableView прокручивал вверх


2

Swift 4 через расширение, обрабатывает пустой вид таблицы:

extension UITableView {
    func scrollToTop(animated: Bool) {
        self.setContentOffset(CGPoint.zero, animated: animated);
    }
}

Это не относится к iOS 11.
rmaddy

2

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

extension UITableView {

    func scrollToTop(){

        for index in 0...numberOfSections - 1 {
            if numberOfSections > 0 && numberOfRows(inSection: index) > 0 {
                scrollToRow(at: IndexPath(row: 0, section: index), at: .top, animated: true)
                break
            }

            if index == numberOfSections - 1 {
                setContentOffset(.zero, animated: true)
                break
            }
        }

    }

}

1

Я должен был добавить умножение -1 *на сумму в строке состояния и панели навигации, потому что она уходила на ту высоту от экрана,

self.tableView.setContentOffset(CGPointMake(0 , -1 * 
  (self.navigationController!.navigationBar.height +  
  UIApplication.sharedApplication().statusBarFrame.height) ), animated:true)

1

быстро

ваш ряд = selectioncellRowNumber вашего раздела, если у вас есть = selectionNumber, если вы не установили, равен нулю

//UITableViewScrollPosition.Middle или Bottom или Top

var lastIndex = NSIndexPath(forRow:  selectioncellRowNumber, inSection: selectionNumber)
self.tableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)



0

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

[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];

[_tableContent scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];

[UIView commitAnimations];

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.