UITableView - faites défiler vers le haut


393

Dans ma vue tableau, je dois faire défiler vers le haut. Mais je ne peux pas garantir que le premier objet sera la section 0, ligne 0. Peut-être que ma vue de table commencera à partir de la section numéro 5.

Je reçois donc une exception lorsque j'appelle:

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

Existe-t-il une autre façon de faire défiler vers le haut de la vue tableau?

Réponses:


857

UITableView est une sous-classe d'UIScrollView, vous pouvez donc également utiliser:

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

Ou

[mainTableView setContentOffset:CGPointZero animated:YES];

Et dans Swift:

mainTableView.setContentOffset(CGPointZero, animated:true)

Et dans Swift 3 et supérieur:

mainTableView.setContentOffset(.zero, animated: true)

9
J'ai d'abord essayé cela avec CGRectZero, qui est équivalent à CGRectMake (0, 0, 0, 0). Cela ne fonctionne pas, mais curieusement, ce qui précède fonctionne. Je suppose qu'il a besoin d'une largeur et d'une hauteur positives. Je vous remercie.
Keller

5
Remarque, vous voudrez animée: NON si vous l'exécutez dans scrollToRowAtIndexPath: afin de faire démarrer la table dans la position correcte. J'espère que cela aide!
Fattie

3
@ hasan83 CGRectMake (0, 0, 0, 0) ou CGRectZero n'est pas un rect visible. Je dirais également que [mainTableView setContentOffset: CGPointZero animated: YES]; est l'expression la plus jolie.
catlan

8
quelqu'un a remarqué que dans iOS11 tout cela est cassé et ne défile pas correctement dans certains cas?
Peter Lapisu

11
@PeterLapisu self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)semble fonctionner dans iOS 11
Jordan S

246

Remarque : cette réponse n'est pas valide pour iOS 11 et versions ultérieures.

je préfère

[mainTableView setContentOffset:CGPointZero animated:YES];

Si vous avez un encart supérieur sur votre vue de table, vous devez le soustraire:

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

12
Tomate, tomate. Hmm ... Cela ne ressort pas très clairement par écrit.
FreeAsInBeer

14
C'est la meilleure façon de l'utiliser lorsque vous avez des vues d'en-tête ou de pied de page de table et que vous souhaitez également les inclure.
mafonya

6
C'est en effet un code clair, mais cela ne fonctionne pas lorsque votre tableViewa une valeur non nulle contentInsetpar le haut. Par exemple: tableView.contentInset = UIEdgeInsetsMake(5.0f, 0.0f, 250.0f, 0.0f);. Si tel est le cas, dans votre code, tableViewdéfile jusqu'à (0.0f, 5.0f).
tolgamorf

25
La solution à mon commentaire précédent:[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
tolgamorf

3
Sur iOS 11, vous devriez envisager d'utiliser -scrollView.adjustedContentInset.topplutôt.
Marián Černý

79

Actions possibles:

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

Désactiver le défilement vers le haut:

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

Modifiez-le et utilisez-le selon les exigences.

Swift 4

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

C'est la solution, parfaite - scrollToFirstRow
Mehul

Excellent résumé. Lorsque vous avez des en-têtes de section, vous devrez utiliser l'option4 scrollToHeader.
Vincent

Existe-t-il un moyen de faire défiler jusqu'à une barre de recherche située au-dessus de Tableview?
Tyler Rutt du

27

Il vaut mieux ne pas utiliser NSIndexPath (table vide), ni supposer que le point haut est CGPointZero (encarts de contenu), c'est ce que j'utilise -

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

J'espère que cela t'aides.


N'est plus valide à partir d'iOS 11.
rmaddy

21

Swift 4 :

Cela fonctionne très 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
Pas si vous avez un tableHeaderView dans votre tableView et qu'il est en ligne (fait défiler le contenu)
finneycanhelp

1
J'ai à la fois un simple et un UITableViewStyleGrouped(les en-têtes défilent avec le contenu) et ce code fonctionne. Assurez-vous que vous êtes dans le thread principal et que vous lancez ce code après que la vue s'affiche ( viewDidAppear). Si vous avez toujours des problèmes, essayez de mettre le code à l'intérieur de ceci:DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: { // the code }
Alessandro Ornano

1
Je vous remercie. Cela vous amènera à la première cellule. Cependant, il n'affiche pas l'en-tête de la vue de table.
finneycanhelp

Cela échouera si la tableView est vide pour une raison quelconque (pas de cellule dans la section 0 à la ligne 0)
Maxim Skryabin

17

J'ai rencontré un problème appelant à essayer certaines des méthodes sur un espace vide tableView. Voici une autre option pour Swift 4 qui gère les vues de table vides.

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

Usage:

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

Cela ne prend en compte aucun en-tête de table ou en-tête de section.
rmaddy

16

NE PAS UTILISER

 tableView.setContentOffset(.zero, animated: true)

Il peut parfois mal régler le décalage. Par exemple, dans mon cas, la cellule était en fait légèrement au-dessus de la vue avec des encarts de zone de sécurité. Pas bon.

UTILISATION AU LIEU

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

1
Solution parfaite.
Baby Groot

Exactement ce que je cherchais, merci.
Simon

Aucune de ces solutions n'est valable. Le premier ne fonctionne pas sous iOS 11 ou version ultérieure. La seconde ne fonctionne pas si la vue de table a un en-tête de table ou la première section a un en-tête de section, sauf si vous voulez vraiment la première ligne en haut et ne vous souciez pas d'afficher les en-têtes.
rmaddy

@rmaddy quelle est la meilleure solution?
ScottyBlades

15

Sur iOS 11, utilisez adjustedContentInsetpour faire défiler correctement vers le haut dans les deux cas lorsque la barre d'état en cours d'appel est visible ou non.

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

Rapide:

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

Pour les tables qui ont un contentInset, définir le décalage de contenu sur CGPointZerone fonctionnera pas. Il défilera vers le haut du contenu contre le défilement vers le haut de la table.

La prise en compte du contenu inséré produit ceci à la place:

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

1
Merci, j'ai continué à le définir sur CGPointZero et je ne pouvais pas comprendre pourquoi cela se produisait.
johnrechd

N'est plus valide à partir d'iOS 11.
rmaddy

10

Ce code vous permet de faire défiler une section spécifique vers le haut

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

C'était le code le plus simple et cela fonctionnait bien. J'ai en fait mis CGPointMake (0.0f, 0.0f). À votre santé!
Felipe

Ce code est très utile pour faire défiler la section
srinivas n

8

Rapide:

tableView.setContentOffset(CGPointZero, animated: true)

N'est plus valide à partir d'iOS 11.
rmaddy

8

Swift 3

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

si tableView.setContentOffset ça ne marche pas.

Utilisation:

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

1
Ce n'est pas valable pour iOS 11 ou version ultérieure.
rmaddy

7

Puisque mon tableViewest plein de toutes sortes d'encarts, c'était la seule chose qui fonctionnait 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)
}

cela m'a été plus utile
Tejzeratul

excellente réponse, appréciez-le
Jeremy Bader

7

En plus de ce qui a déjà été dit, vous pouvez créer une extension (Swift) ou une catégorie (Objectif C) pour faciliter cela à l'avenir:

Rapide:

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

Chaque fois que vous souhaitez faire défiler une table donnée vers le haut, vous pouvez appeler le code suivant:

tableView.scrollToTop(animated: true)

2
N'est plus valide à partir d'iOS 11.
rmaddy

6

Je préfère ce qui suit, car il prend en compte un encart. S'il n'y a pas d'encart, il défilera toujours vers le haut car l'encart sera 0.

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

N'est plus valide à partir d'iOS 11.
rmaddy

5

Rapide :

si vous n'avez pas d'en-tête tableView:

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

si c'est le cas :

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

5

Swift 5, iOS 13

Je sais que cette question a déjà beaucoup de réponses mais d'après mon expérience, il n'y a qu'une seule méthode qui fonctionne toujours:

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

Si vous travaillez en asynchrone, des tableaux qui s'animent avec des claviers, etc., les autres réponses défilent souvent vers le bas presque pas vers le bas absolu. Cette méthode vous mènera à la fin absolue d'une table à chaque fois.


Vous devez également vérifier s'il y a une section
Onur Tuna

4

Voici ce que j'utilise pour fonctionner correctement sur 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

Dans Swift 5, merci beaucoup @ la réponse d'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)
        }
    }

}

Usage:

tableView.scrollToTop()

2
1. Ceci est également valable dans Swift 4. 2. Cela ne fonctionne pas s'il y a un en-tête de table ou un en-tête de section.
rmaddy

3

utiliser contentOffset n'est pas la bonne façon. ce serait mieux car c'est la façon naturelle de voir la table

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

2
Cela ne fonctionnera pas s'il y a un en-tête de table ou un en-tête de section.
rmaddy

3

C'était le seul extrait de code qui fonctionnait pour moi

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 est la hauteur de ma cellule d'en-tête et de vue de table


C'est loin d'être la bonne façon de faire défiler vers le haut. Cela n'a aucun sens d'utiliser trois lignes distinctes juste pour définir le décalage du contenu. Seule la dernière ligne est nécessaire, mais le codage en dur d'un décalage spécifique n'est pas la bonne solution.
rmaddy

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

appelez cette fonction où vous voulez UITableView faites défiler vers le haut


2

Swift 4 via l'extension, gère la vue de table vide:

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

Ce n'est pas valable à partir d'iOS 11.
rmaddy

2

J'utilise tabBarController et j'ai quelques sections dans ma table à chaque onglet, c'est donc la meilleure solution pour moi.

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

J'ai dû ajouter la multiplication par -1 *à la somme de la barre d'état et de la barre de navigation, parce que cette hauteur disparaissait de l'écran,

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

1

en rapide

votre ligne = selectioncellRowNumber votre section si vous avez = selectionNumber si vous n'avez pas défini est à zéro

//UITableViewScrollPosition.Middle ou Bottom or Top

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

1

Voici le code pour faire défilerTableView To Top par programme

Rapide:

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

1

Dans Swift-3:

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

0

Si vous souhaitez déplacer l'animation de défilement dans le tableau, utilisez ce code. Le défilement se déplace vers le haut avec une animation en 0,5 seconde.

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

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

[UIView commitAnimations];

0

Avec Swift:

self.scripSearchView.quickListTbl?.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.