UITableView - desplazarse hacia arriba

393

En mi vista de tabla tengo que desplazarme hacia la parte superior. Pero no puedo garantizar que el primer objeto sea la sección 0, fila 0. Puede que mi vista de tabla comience desde la sección número 5.

Entonces recibo una excepción cuando llamo:

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

¿Hay otra forma de desplazarse a la parte superior de la vista de tabla?

Ilya Suzdalnitski
fuente

Respuestas:

857

UITableView es una subclase de UIScrollView, por lo que también puede usar:

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

O

[mainTableView setContentOffset:CGPointZero animated:YES];

Y en Swift:

mainTableView.setContentOffset(CGPointZero, animated:true)

Y en Swift 3 y superior:

mainTableView.setContentOffset(.zero, animated: true)
catlan
fuente
99
Primero probé esto con CGRectZero, que es equivalente a CGRectMake (0, 0, 0, 0). Esto no funciona, pero curiosamente lo anterior sí. Supongo que necesita un ancho y una altura positivos. Gracias.
Keller
55
Tenga en cuenta que querrá animación: NO si ejecuta esto en scrollToRowAtIndexPath: para que la tabla comience en la posición correcta. ¡Espero eso ayude!
Fattie
3
@ hasan83 CGRectMake (0, 0, 0, 0) o CGRectZero no es un rectángulo visible. También diría que [mainTableView setContentOffset: CGPointZero animated: YES]; Es la expresión más bonita.
catlan
8
¿Alguien notó que en iOS11 todo esto está roto y no se desplaza correctamente en algunos casos?
Peter Lapisu
11
@PeterLapisu self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)parece funcionar en iOS 11
Jordan S
246

Nota : esta respuesta no es válida para iOS 11 y versiones posteriores.

yo prefiero

[mainTableView setContentOffset:CGPointZero animated:YES];

Si tiene un recuadro superior en su vista de tabla, debe restarlo:

[mainTableView setContentOffset:CGPointMake(0.0f, -mainTableView.contentInset.top) animated:YES];
fabb
fuente
12
Tomate, tomate. Hmm ... Eso no se ve muy claramente por escrito.
FreeAsInBeer
14
Esta es la mejor manera de usarla cuando tiene vistas de encabezado o pie de página y desea que se incluyan también.
mafonya
66
Este es de hecho un código claro, pero no funciona cuando tableViewtiene un valor distinto de cero contentInsetdesde la parte superior. Por ejemplo: tableView.contentInset = UIEdgeInsetsMake(5.0f, 0.0f, 250.0f, 0.0f);. Si ese es el caso, en su código se tableViewdesplaza a (0.0f, 5.0f).
tolgamorf
25
La solución a mi comentario anterior:[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
tolgamorf
3
En iOS 11 deberías considerar usarlo en su -scrollView.adjustedContentInset.toplugar.
Marián Černý
79

Posibles acciones:

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 4

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

5 5

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

Deshabilitar Desplazarse hacia arriba:

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

Modifíquelo y úselo según los requisitos.

Swift 4

  func scrollToFirstRow() {
    let indexPath = IndexPath(row: 0, section: 0)
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
  }
AG
fuente
Esa es la solución, perfecto - scrollToFirstRow
Mehul
Excelente resumen Cuando tenga encabezados de sección, deberá usar la opción 4 scrollToHeader.
Vincent
¿Hay alguna manera de desplazarse hacia arriba a una barra de búsqueda que está encima de la Vista de tabla?
Tyler Rutt el
27

Es mejor no usar NSIndexPath (tabla vacía), ni suponer que el punto superior es CGPointZero (insertos de contenido), eso es lo que uso:

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

Espero que esto ayude.

Kof
fuente
Ya no es válido a partir de iOS 11.
rmaddy
21

Swift 4 :

Esto funciona muy bien:

//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)
Alessandro Ornano
fuente
3
No, si tiene un tableHeaderView en su tableView y está en línea (se desplaza con el contenido)
finneycanhelp
1
Tengo tanto un plano como un UITableViewStyleGrouped(los encabezados se desplazan con el contenido) y este código funciona. Asegúrese de estar en el hilo principal e inicie este código después de que aparezca la vista ( viewDidAppear). Si todavía tiene problemas, intente poner el código dentro de esto:DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: { // the code }
Alessandro Ornano
1
Gracias. Te llevará a la primera celda. Sin embargo, no muestra el encabezado de la vista de tabla.
finneycanhelp
Esto fallará si tableView está vacío por alguna razón (no hay celda en la sección 0 en la fila 0)
Maxim Skryabin
17

He encontrado un problema al llamar a probar algunos de los métodos en vacío tableView. Aquí hay otra opción para Swift 4 que maneja vistas de tabla vacías.

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
Adrian
fuente
Esto no tiene en cuenta ningún encabezado de tabla o encabezado de sección.
rmaddy
16

NO USE

 tableView.setContentOffset(.zero, animated: true)

A veces puede establecer el desplazamiento incorrectamente. Por ejemplo, en mi caso, la celda estaba en realidad ligeramente por encima de la vista con insertos de área segura. No está bien.

USO EN LUGAR

 tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
ScottyBlades
fuente
1
Solución perfecta.
Baby Groot
Exactamente lo que estaba buscando, gracias.
Simon
Ninguna de estas soluciones es válida. El primero no funciona con iOS 11 o posterior. La segunda no funciona si la vista de tabla tiene un encabezado de tabla o la primera sección tiene un encabezado de sección a menos que realmente desee la primera fila en la parte superior y no le importe mostrar ningún encabezado.
rmaddy
@rmaddy ¿cuál es la mejor solución?
ScottyBlades
15

En iOS 11, use adjustedContentInsetpara desplazarse correctamente hacia arriba para ambos casos cuando la barra de estado de la llamada está visible o no.

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)
}
Thanh Pham
fuente
12

Para las tablas que tienen a contentInset, establecer el desplazamiento del contenido en CGPointZerono funcionará. Se desplazará a la parte superior del contenido frente a la parte superior de la tabla.

Tener en cuenta la inserción de contenido produce esto en su lugar:

[tableView setContentOffset:CGPointMake(0, -tableView.contentInset.top) animated:NO];
Eran Goldin
fuente
1
Gracias, seguí configurándolo en CGPointZero y no podía entender por qué sucedía esto.
johnrechd
Ya no es válido a partir de iOS 11.
rmaddy
10

Este código te permite desplazarte por una sección específica hacia arriba

CGRect cellRect = [tableinstance rectForSection:section];
CGPoint origin = [tableinstacne convertPoint:cellRect.origin 
                                    fromView:<tableistance>];
[tableinstance setContentOffset:CGPointMake(0, origin.y)];
Ramesh Muthe
fuente
Este fue el código más simple y funcionó bien. De hecho, puse CGPointMake (0.0f, 0.0f). ¡Salud!
Felipe
Este código es muy útil para hacer que la sección se desplace hacia arriba
srinivas n
8

Rápido:

tableView.setContentOffset(CGPointZero, animated: true)
Esqarrouth
fuente
Ya no es válido a partir de iOS 11.
rmaddy
8

Swift 3

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

si tableView.setContentOffsetno funciona

Utilizar:

tableView.beginUpdates()
tableView.setContentOffset(CGPoint.zero, animated: true)
tableView.endUpdates()
Исмаил Хасбулатов
fuente
1
Esto no es válido para iOS 11 o posterior.
rmaddy
7

Como mi tableViewestá lleno de todo tipo de insertos, esto fue lo único que funcionó bien:

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)
}
budidino
fuente
esto fue más útil para mí
Tejzeratul
gran respuesta, lo aprecio
Jeremy Bader
7

Además de lo que ya se ha dicho, puede crear una extensión (Swift) o una categoría (Objetivo C) para facilitar esto en el futuro:

Rápido:

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

Cada vez que desee desplazar cualquier tabla vista hasta la parte superior puede llamar al siguiente código:

tableView.scrollToTop(animated: true)
ocwang
fuente
2
Ya no es válido a partir de iOS 11.
rmaddy
6

Prefiero lo siguiente, ya que tiene en cuenta un recuadro. Si no hay ningún recuadro, seguirá desplazándose hacia arriba, ya que el recuadro será 0.

tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: true)
jacob
fuente
Ya no es válido a partir de iOS 11.
rmaddy
5

Rápido:

si no tiene encabezado tableView:

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

si es así :

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

Swift 5, iOS 13

Sé que esta pregunta ya tiene muchas respuestas, pero según mi experiencia, solo hay un método que siempre funciona:

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

Si está trabajando en asíncrono, las tablas que animado con los teclados, etc., las otras respuestas a menudo se desplazamiento para el casi , no el fondo absoluto inferior. Este método lo llevará al final absoluto de una tabla cada vez.

bsod
fuente
También debe verificar si hay una sección
Onur Tuna
4

Esto es lo que uso para funcionar correctamente en 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)
    }
}
Hans Brende
fuente
4

En Swift 5, gracias @ Adrian responde mucho

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()
dengST30
fuente
2
1. Esto también es válido en Swift 4. 2. Esto no funciona si hay un encabezado de tabla o un encabezado de sección.
rmaddy
3

Usar contentOffset no es la forma correcta. esto sería mejor ya que es la forma natural de la vista de tabla

tableView.scrollToRow(at: NSIndexPath.init(row: 0, section: 0) as IndexPath, at: .top, animated: true)
Gulz
fuente
2
Esto no funcionará si hay un encabezado de tabla o un encabezado de sección.
rmaddy
3

Este fue el único fragmento de código que funcionó para mí

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 es la altura de mi celda de vista de encabezado y tabla

jimmyruby
fuente
Esto está lejos de ser la forma correcta de desplazarse hacia la parte superior. No tiene sentido usar tres líneas separadas solo para establecer el desplazamiento del contenido. Solo se necesita la última línea, pero codificar un desplazamiento específico no es la solución correcta.
rmaddy
2
func scrollToTop() {
        NSIndexPath *topItem = [NSIndexPath indexPathForItem:0 inSection:0];
        [tableView scrollToRowAtIndexPath:topItem atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

llama a esta función donde quieras UITableView desplaza hacia arriba

Sayali Shinde
fuente
2

Swift 4 a través de la extensión, maneja la vista de tabla vacía:

extension UITableView {
    func scrollToTop(animated: Bool) {
        self.setContentOffset(CGPoint.zero, animated: animated);
    }
}
Shawn
fuente
Esto no es válido a partir de iOS 11.
rmaddy
2

Uso tabBarController y tengo algunas secciones en mi vista de tabla en cada pestaña, así que esta es la mejor solución para mí.

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

    }

}
Okan
fuente
1

Tuve que agregar la multiplicación por -1 *a la suma de la barra de estado y la barra de navegación, porque iba a esa altura de la pantalla,

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

en rápido

su fila = selectioncellRowNumber su sección si tiene = selectionNumber si no tiene set es cero

//UITableViewScrollPosition.Middle o Bottom o Top

var lastIndex = NSIndexPath(forRow:  selectioncellRowNumber, inSection: selectionNumber)
self.tableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
idris yıldız
fuente
1

Aquí está el código para ScrollTableView To Top Programatic

Rápido:

self.TableView.setContentOffset(CGPointMake(0, 1), animated:true)
Kavin Kumar Arumugam
fuente
1

En Swift-3:

self.tableView.setContentOffset(CGPoint.zero, animated: true)
Jeni Khant
fuente
0

Si desea mover la animación de desplazamiento en la tabla, use este código. El desplazamiento se mueve hacia arriba con animación en .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];
Matheus Veloza
fuente
0

Con Swift:

self.scripSearchView.quickListTbl?.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
Dhananjay Patil
fuente