UITableView - scorrere verso l'alto


393

Nella mia vista tabella devo scorrere verso l'alto. Ma non posso garantire che il primo oggetto sarà la sezione 0, riga 0. Potrebbe essere che la vista della mia tabella inizierà dalla sezione numero 5.

Quindi ricevo un'eccezione quando chiamo:

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

C'è un altro modo per scorrere fino alla cima della vista tabella?

Risposte:


857

UITableView è una sottoclasse di UIScrollView, quindi puoi anche usare:

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

O

[mainTableView setContentOffset:CGPointZero animated:YES];

E in Swift:

mainTableView.setContentOffset(CGPointZero, animated:true)

E in Swift 3 e versioni successive:

mainTableView.setContentOffset(.zero, animated: true)

9
L'ho provato per la prima volta con CGRectZero, che equivale a CGRectMake (0, 0, 0, 0). Questo non funziona, ma stranamente quanto sopra funziona. Immagino che abbia bisogno di una larghezza e un'altezza positive. Grazie.
Keller,

5
Nota, vuoi animare: NO se lo esegui in scrollToRowAtIndexPath: in modo da far iniziare la tabella nella posizione corretta. Spero che sia d'aiuto!
Fattie,

3
@ hasan83 CGRectMake (0, 0, 0, 0) o CGRectZero non è un rettangolo visibile. Direi anche che [mainTableView setContentOffset: CGPointZero animato: SÌ]; è l'espressione più bella.
catlan,

8
qualcuno ha notato che in iOS11 tutto è rotto e in alcuni casi non scorre correttamente?
Peter Lapisu,

11
@PeterLapisu self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)sembra funzionare su iOS 11
Jordan S

246

Nota : questa risposta non è valida per iOS 11 e versioni successive.

preferisco

[mainTableView setContentOffset:CGPointZero animated:YES];

Se nella vista tabella è presente un riquadro superiore, è necessario sottrarlo:

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

12
Pomodoro, Pomodoro. Hmm ... Non è molto chiaro per iscritto.
FreeAsInBeer

14
Questo è il modo migliore da utilizzare quando si dispone di viste di intestazione o piè di tabella e si desidera che vengano incluse anche queste.
mafonya,

6
Questo è davvero un codice chiaro, ma non funziona quando il tuo tableViewè diverso contentInsetda zero dall'alto. Ad esempio: tableView.contentInset = UIEdgeInsetsMake(5.0f, 0.0f, 250.0f, 0.0f);. In tal caso, nel tuo codice tableViewscorre fino a (0.0f, 5.0f).
tolgamorf

25
La soluzione al mio commento precedente:[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
tolgamorf

3
Su iOS 11 dovresti -scrollView.adjustedContentInset.topinvece considerare l'utilizzo .
Marián Černý

79

Possibili azioni:

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

Disabilita Scorri verso l'alto:

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

Modificalo e usalo secondo i requisiti.

Swift 4

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

Questa è la soluzione, perfetta - scrollToFirstRow
Mehul

Riepilogo eccellente. Quando hai le intestazioni di sezione dovrai usare option4 scrollToHeader.
Vincent

C'è un modo per scorrere fino a una barra di ricerca che si trova sopra Tableview?
Tyler Rutt,

27

È meglio non usare NSIndexPath (tabella vuota), né supporre che il punto più alto sia CGPointZero (inserimenti di contenuti), ecco cosa io uso -

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

Spero che sia di aiuto.


Non più valido a partire da iOS 11.
rmaddy,

21

Swift 4 :

Funziona molto bene:

//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
Non se hai un tableHeaderView nel tuo tableView ed è in linea (scorre con il contenuto)
finneycanhelp

1
Ho sia una semplice che una UITableViewStyleGrouped(scorre le intestazioni con il contenuto) e questo codice funziona. Assicurati di essere nel thread principale e avvii questo codice dopo la visualizzazione ( viewDidAppear). Se hai ancora problemi prova a inserire il codice all'interno di questo:DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: { // the code }
Alessandro Ornano,

1
Grazie. Ti porterà alla prima cella. Tuttavia, non mostra l'intestazione della vista tabella.
finneycanhelp,

Questo fallirà se tableView è vuoto per qualche motivo (nessuna cella nella sezione 0 alla riga 0)
Maxim Skryabin

17

Ho riscontrato un problema durante la chiamata provando alcuni dei metodi su un vuoto tableView. Ecco un'altra opzione per Swift 4 che gestisce le visualizzazioni di tabella vuote.

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

Questo non tiene conto di alcuna intestazione di tabella o intestazione di sezione.
rmaddy,

16

NON USARE

 tableView.setContentOffset(.zero, animated: true)

A volte può impostare l'offset in modo errato. Ad esempio, nel mio caso, la cella era in realtà leggermente sopra la vista con inserti di area sicura. Non bene.

INSTEAD USE

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

1
Soluzione perfetta.
Baby Groot,

Esattamente quello che stavo cercando, grazie.
Simon,

Nessuna di queste soluzioni è valida. Il primo non funziona con iOS 11 o versioni successive. Il secondo non funziona se la vista tabella ha un'intestazione di tabella o la prima sezione ha un'intestazione di sezione a meno che tu non voglia davvero la prima riga in alto e non ti interessi mostrare le intestazioni.
rmaddy,

@rmaddy qual è la soluzione migliore?
ScottyBlades,

15

Su iOS 11, utilizzare adjustedContentInsetper scorrere correttamente verso l'alto per entrambi i casi quando la barra di stato della chiamata è visibile o meno.

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

Per le tabelle con a contentInset, l'impostazione dell'offset del contenuto su CGPointZeronon funzionerà. Scorrerà fino al contenuto superiore rispetto allo scorrimento verso il piano del tavolo.

La presa in considerazione dell'inserzione del contenuto produce invece questo:

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

1
Grazie, ho continuato a impostarlo su CGPointZero e non riuscivo a capire perché questo stesse accadendo.
johnrechd,

Non più valido a partire da iOS 11.
rmaddy

10

Questo codice consente di scorrere una sezione specifica verso l'alto

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

Questo era il codice più semplice e funzionava bene. In realtà ho messo CGPointMake (0.0f, 0.0f). Saluti!
Felipe,

Questo codice è molto utile per far scorrere la sezione top
srinivas n

8

Swift:

tableView.setContentOffset(CGPointZero, animated: true)

Non più valido a partire da iOS 11.
rmaddy

8

Swift 3

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

se tableView.setContentOffsetnon funziona.

Uso:

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

1
Questo non è valido per iOS 11 o versioni successive.
rmaddy,

7

Poiché il mio tableViewè pieno di tutti i tipi di inserti, questa è stata l'unica cosa che ha funzionato bene:

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

questo mi è stato più utile
Tejzeratul,

ottima risposta, apprezzalo
Jeremy Bader

7

Aggiungendo ciò che è già stato detto, puoi creare un'estensione (Swift) o una categoria (Obiettivo C) per renderlo più facile in futuro:

Swift:

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

Ogni volta che vuoi scorrere un dato tavolo Visualizza verso l'alto puoi chiamare il seguente codice:

tableView.scrollToTop(animated: true)

2
Non più valido a partire da iOS 11.
rmaddy

6

Preferisco quanto segue, poiché tiene conto di un inserto. Se non ci sono inserti, scorrerà comunque verso l'alto poiché l'inserto sarà 0.

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

Non più valido a partire da iOS 11.
rmaddy

5

Veloce:

se non si dispone dell'intestazione tableView:

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

se è così :

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

5

Swift 5, iOS 13

So che questa domanda ha già molte risposte ma dalla mia esperienza, c'è solo un metodo che funziona sempre:

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

Se si lavora in asincrona, le tabelle che animano con le tastiere, ecc, le altre risposte spesso di scorrimento per la quasi fondo, non il fondo assoluto. Questo metodo ti porterà alla fine assoluta di una tabella ogni volta.


Devi anche controllare se c'è una sezione
Onur Tuna

4

Ecco cosa uso per funzionare correttamente su 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

In Swift 5, grazie mille alla risposta di Adrian

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. Questo vale anche in Swift 4. 2. Non funziona se è presente un'intestazione di tabella o un'intestazione di sezione.
rmaddy,

3

usando contentOffset non è il modo giusto. questo sarebbe meglio in quanto è il modo naturale di visualizzazione tabella

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

2
Questo non funzionerà se è presente un'intestazione di tabella o un'intestazione di sezione.
rmaddy,

3

Questo è stato l'unico frammento di codice che ha funzionato per me

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 è l'altezza della mia intestazione e della cella di visualizzazione tabella


Questo è tutt'altro che il modo corretto di scorrere verso l'alto. Non ha senso usare tre linee separate solo per impostare l'offset del contenuto. È necessaria solo l'ultima riga, ma codificare un offset specifico non è la soluzione corretta.
rmaddy,

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

chiama questa funzione ovunque desideri UITableView scorrere verso l'alto


2

Swift 4 tramite estensione, gestisce la vista tabella vuota:

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

Questo non è valido a partire da iOS 11.
rmaddy

2

Uso tabBarController e ho una sezione nella mia vista tabella in ogni scheda, quindi questa è la soluzione migliore per me.

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

Ho dovuto aggiungere il moltiplicatore -1 *per la somma della barra di stato e della barra di navigazione, perché stava andando a tale altezza dallo schermo,

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

1

in fretta

your row = selectioncellRowNumber la tua sezione se hai = selectionNumber se non hai impostato è pari a zero

//UITableViewScrollPosition.Middle o Bottom o Top

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

1

Ecco il codice di ScrollTableView all'inizio programmaticamente

Swift:

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

1

In Swift-3:

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

0

Se desideri spostare l'animazione di scorrimento nella tabella, utilizza questo codice. Lo scorrimento si sposta verso l'alto con l'animazione in 0,5 secondi.

[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)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.