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.