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?

Ilya Suzdalnitski
la source

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)
catlan
la source
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];
fabb
la source
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)
  }
AG
la source
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.

Kof
la source
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)
Alessandro Ornano
la source
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
Adrian
la source
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)
ScottyBlades
la source
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)
}
Thanh Pham
la source
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];
Eran Goldin
la source
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)];
Ramesh Muthe
la source
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)
Esqarrouth
la source
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()
Исмаил Хасбулатов
la source
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)
}
budidino
la source
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)
ocwang
la source
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)
Jacob
la source
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)
jmcastel
la source
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.

bsod
la source
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)
    }
}
Hans Brende
la source
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()
dengST30
la source
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)
Gulz
la source
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

jimmyruby
la source
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

Sayali Shinde
la source
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);
    }
}
Shawn
la source
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
            }
        }

    }

}
Okan
la source
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)
Carlos.V
la source
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)
idris yıldız
la source
1

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

Rapide:

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

Dans Swift-3:

self.tableView.setContentOffset(CGPoint.zero, animated: true)
Jeni Khant
la source
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];
Matheus Veloza
la source
0

Avec Swift:

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