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?

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)

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];

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

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.


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)

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

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)

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

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];

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)];

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)

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

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

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)

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)

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)

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.


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

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

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)

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


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


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

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

    }

}

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)

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)

1

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

Rápido:

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

1

En Swift-3:

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

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];

0

Con Swift:

self.scripSearchView.quickListTbl?.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.