UITableView - role para o topo


393

Na minha exibição de tabela, tenho que rolar para o topo. Mas não posso garantir que o primeiro objeto seja a seção 0, linha 0. Pode ser que minha exibição de tabela comece na seção número 5.

Então, recebo uma exceção quando ligo para:

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

Existe outra maneira de rolar para o topo da exibição da tabela?

Respostas:


857

UITableView é uma subclasse de UIScrollView, portanto você também pode usar:

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

Ou

[mainTableView setContentOffset:CGPointZero animated:YES];

E em Swift:

mainTableView.setContentOffset(CGPointZero, animated:true)

E no Swift 3 e acima:

mainTableView.setContentOffset(.zero, animated: true)

9
Eu tentei isso pela primeira vez com CGRectZero, que é equivalente a CGRectMake (0, 0, 0, 0). Isso não funciona, mas estranhamente o acima. Eu acho que precisa de uma largura e altura positivas. Obrigado.
Keller

5
Observe que você desejará animação: NO se você executar isso em scrollToRowAtIndexPath: para fazer a tabela iniciar na posição correta. Espero que ajude!
Fattie

3
@ hasan83 CGRectMake (0, 0, 0, 0) ou CGRectZero não é um ret visível. Eu também diria que [mainTableView setContentOffset: CGPointZero animated: YES]; é a expressão mais bonita.
catlan

8
alguém notou que no iOS11 tudo isso está quebrado e não rola corretamente em alguns casos?
Peter Lapisu

11
@PeterLapisu self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)parece funcionar no iOS 11
Jordan S

246

Nota : Esta resposta não é válida para iOS 11 e posterior.

eu prefiro

[mainTableView setContentOffset:CGPointZero animated:YES];

Se você tem uma inserção superior na visualização da tabela, é necessário subtraí-la:

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

12
Tomate, tomate. Hmm ... Isso não aparece muito claramente por escrito.
FreeAsInBeer

14
Essa é a melhor maneira de usar quando você tem vistas de cabeçalho ou rodapé da tabela e deseja que elas sejam incluídas também.
precisa saber é

6
Este é realmente um código claro, mas não funciona quando o seu tableViewnão é zero a contentInsetpartir do topo. Por exemplo: tableView.contentInset = UIEdgeInsetsMake(5.0f, 0.0f, 250.0f, 0.0f);. Se for esse o caso, no seu código a tableViewrolagem para (0.0f, 5.0f).
tolgamorf

25
A solução para o meu comentário anterior:[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
tolgamorf 8/13

3
No iOS 11, você deve considerar o uso -scrollView.adjustedContentInset.top.
Marián Černý

79

Ações possíveis:

1 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)
}

Desativar Rolar para cima:

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)
    }
}

Modifique e use-o conforme o requisito.

Swift 4

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

Essa é a solução, perfeita - scrollToFirstRow
Mehul

Excelente resumo. Quando você tiver cabeçalhos de seção, precisará usar a opção 4 scrollToHeader.
Vincent

Existe uma maneira de rolar até uma barra de pesquisa acima da Tableview?
Tyler Rutt

27

É melhor não usar NSIndexPath (tabela vazia), nem assumir que o ponto principal é CGPointZero (inserções de conteúdo), é isso que eu uso -

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

Espero que isto ajude.


Não é mais válido a partir do iOS 11.
rmaddy 03/08/19

21

Swift 4 :

Isso funciona muito bem:

//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
Não, se você tem um tableHeaderView em sua tableView e é inline (pergaminhos com o conteúdo)
finneycanhelp

11
Eu tenho um simples e um UITableViewStyleGrouped(cabeçalhos rola com o conteúdo) e esse código funciona. Certifique-se de estar no segmento principal e de ativar esse código após a exibição ( viewDidAppear). Se você ainda tiver problemas, tente colocar o código dentro deste:DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: { // the code }
Alessandro Ornano

11
Obrigado. Você será direcionado para a primeira célula. No entanto, ele não mostra o cabeçalho da exibição de tabela.
finneycanhelp

Isto irá falhar se o tableView está vazia por algum motivo (nenhuma célula em 0 seção de 0 linha)
Maxim Skryabin

17

Eu encontrei um problema ao tentar alguns dos métodos em um vazio tableView. Aqui está outra opção para o Swift 4 que lida com visualizações de tabletes vazias.

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)
    }
  }
}

Uso:

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

Isso não considera nenhum cabeçalho de tabela ou cabeçalho de seção.
Rddydy 3/08

16

NÃO UTILIZE

 tableView.setContentOffset(.zero, animated: true)

Às vezes, pode definir o deslocamento incorretamente. Por exemplo, no meu caso, a célula estava realmente um pouco acima da vista com inserções de área segura. Não é bom.

USO EM VEZ

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

11
Solução perfeita.
Bebê Groot

Exatamente o que eu estava procurando, obrigado.
24419 Simon

Nenhuma dessas soluções é válida. O primeiro não funciona no iOS 11 ou posterior. A segunda não funciona se a exibição da tabela tiver um cabeçalho de tabela ou a primeira seção tiver um cabeçalho de seção, a menos que você realmente queira a primeira linha na parte superior e não se importe em mostrar cabeçalhos.
Rddydy 3/08

@rmaddy qual é a melhor solução?
ScottyBlades

15

No iOS 11, use adjustedContentInsetpara rolar corretamente para o topo nos dois casos, quando a barra de status de chamada estiver visível ou não.

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

Rápido:

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

Para tabelas com a contentInset, definir o deslocamento do conteúdo como CGPointZeronão funcionará. Vai rolar para o topo do conteúdo vs. rolar para o topo da tabela.

Levar em consideração o conteúdo inserido produz isso:

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

11
Obrigado, continuei configurando-o para CGPointZero e não conseguia entender por que isso estava acontecendo.
22418 Johnrechd

Não é mais válido a partir do iOS 11.
rmaddy

10

Este código permite rolar uma seção específica para o topo

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

Este foi o código mais simples e funcionou bem. Na verdade, eu coloquei CGPointMake (0.0f, 0.0f). Felicidades!
Felipe

Este código é muito útil para fazer a seção rolar para cima
srinivas n /


8

Swift 3

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

se tableView.setContentOffsetnão funcionar.

Usar:

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

11
Isso não é válido para o iOS 11 ou posterior.
Rddydy 3/08

7

Como o meu tableViewé cheio de todos os tipos de inserções, essa foi a única coisa que funcionou bem:

Swift 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)
}

isso foi mais útil para mim
Tejzeratul 10/10

ótima resposta, agradeço
Jeremy Bader

7

Além do que já foi dito, você pode criar uma extensão (Swift) ou categoria (objetivo C) para facilitar isso no futuro:

Rápido:

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

Sempre que você desejar rolar qualquer tabelaView para o topo, poderá chamar o seguinte código:

tableView.scrollToTop(animated: true)

2
Não é mais válido a partir do iOS 11.
rmaddy 03/08/19

6

Prefiro o seguinte, pois leva em consideração uma inserção. Se não houver inserção, ela ainda rolará para o topo, pois a inserção será 0.

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

Não é mais válido a partir do iOS 11.
rmaddy 03/08/19

5

Rápido :

se você não tiver o cabeçalho tableView:

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

se então :

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

5

Swift 5, iOS 13

Eu sei que esta pergunta já tem muitas respostas, mas pela minha experiência, existe apenas um método que sempre funciona:

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

Se você estiver trabalhando em assinaturas assíncronas, que são animadas com teclados, etc., as outras respostas costumam rolar para quase o fundo, não o fundo absoluto. Esse método o levará ao final absoluto de uma tabela todas as vezes.


Você também precisa verificar se há uma seção
Onur Atum

4

Aqui está o que eu uso para funcionar corretamente no 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

Em Swift 5, obrigado @ resposta de Adrian muito

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)
        }
    }

}

Uso:

tableView.scrollToTop()

2
1. Isso também é válido no Swift 4. 2. Isso não funciona se houver um cabeçalho de tabela ou de seção.
Rddydy

3

usar contentOffset não é o caminho certo. isso seria melhor, pois é o caminho natural da exibição de tabela

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

2
Isso não funcionará se houver um cabeçalho de tabela ou um cabeçalho de seção.
Rdaddy

3

Este foi o único trecho de código que funcionou para mim

Swift 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 é a altura da minha célula de visualização de cabeçalho e tabela


Isso está longe de ser a maneira correta de rolar para o topo. Não faz sentido usar três linhas separadas apenas para definir o deslocamento do conteúdo. Somente a última linha é necessária, mas codificar um deslocamento específico não é a solução correta.
Rddydy

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

chame essa função onde quiser UITableView, role para o topo


2

Swift 4 via extensão, lida com a exibição de tabela vazia:

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

Este não é válida a partir de iOS 11.
rmaddy

2

Eu uso o tabBarController e tenho algumas seções na minha tableview em cada guia, portanto, essa é a melhor solução para mim.

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

Eu tive que adicionar a multiplicação -1 *à soma da barra de status e da barra de navegação, porque estava saindo dessa altura da tela,

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

1

em rápido

sua linha = selectioncellRowNumber sua seção se você tiver = selectionNumber se você não tiver definido como zero

//UITableViewScrollPosition.Middle ou Bottom ou Top

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

1

Aqui está o código para ScrollTableView para o topo programaticamente

Rápido:

self.TableView.setContentOffset(CGPointMake(0, 1), animated:true)

1

Em Swift-3:

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

0

Se você gostaria de mover a animação de rolagem na tabela, use este código. A rolagem é movida para o topo com animação em 0,5 segundos.

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

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

[UIView commitAnimations];

0

Com Swift:

self.scripSearchView.quickListTbl?.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.