web-dev-qa-db-fra.com

Obtenez UIScrollView pour faire défiler vers le haut

Comment faire défiler un UIScrollView vers le haut?

159
abcd

MISE À JOUR POUR iOS 7

[self.scrollView setContentOffset:
    CGPointMake(0, -self.scrollView.contentInset.top) animated:YES];

ORIGINAL

[self.scrollView setContentOffset:CGPointZero animated:YES];

ou si vous souhaitez conserver la position de défilement horizontal et réinitialiser simplement la position verticale:

[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0)
    animated:YES];
306
rob mayoff

Voici une extension Swift qui facilite les choses:

extension UIScrollView {
    func scrollToTop() {
        let desiredOffset = CGPoint(x: 0, y: -contentInset.top)
        setContentOffset(desiredOffset, animated: true)
   }
}

Usage:

myScrollView.scrollToTop()
51
Andrew Schreiber

iOS 11 et supérieur

essayez de travailler avec le nouveau adjustedContentInset.

Par exemple (défiler vers le haut):

var offset = CGPoint(
    x: -scrollView.contentInset.left, 
    y: -scrollView.contentInset.top)

if #available(iOS 11.0, *) {
    offset = CGPoint(
        x: -scrollView.adjustedContentInset.left, 
        y: -scrollView.adjustedContentInset.top)    
}

scrollView.setContentOffset(offset, animated: true)

Même si vous utilisez prefersLargeTitles, safe area etc.

32
Jakub Truhlář

Pour Swift 4

scrollView.setContentOffset(.zero, animated: true)
29
Rajasekhar Pasupuleti

Utilisez setContentOffset:animated:

[scrollView setContentOffset:CGPointZero animated:YES];
23
Bryan Chen

Réponse pour Swift 2.0/3.0/4.0 et iOS 7+:

let desiredOffset = CGPoint(x: 0, y: -self.scrollView.contentInset.top)
self.scrollView.setContentOffset(desiredOffset, animated: true)
17
worthbak

Dans iOS7, j'avais du mal à faire passer une vue de défilement particulière au sommet, ce qui fonctionnait sous iOS6, et je l'utilisais pour définir le défilement à atteindre.

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
8
hoak

Version Swift 3.0.1 de réponse de rob mayoff :

self.scrollView.setContentOffset(
CGPoint(x: 0,y: -self.scrollView.contentInset.top),
animated: true)
4
Roni Leshes

Pour reproduire entièrement le comportement scrollToTop de la barre d'état, nous devons non seulement définir le contentOffset, mais également nous assurer que les scrollIndicators sont affichés. Sinon, l'utilisateur peut se perdre rapidement.

La seule méthode publique pour y parvenir est flashScrollIndicators. Malheureusement, l'appeler une fois après avoir défini le contentOffset n'a aucun effet car il est réinitialisé immédiatement. J'ai trouvé que ça marche quand on fait le flash à chaque fois dans scrollViewDidScroll:.

// define arbitrary tag number in a global constants or in the .pch file
#define SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG 19291

- (void)scrollContentToTop {
    [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];

    self.scrollView.tag = SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        self.scrollView.tag = 0;
    });
}

Dans votre UIScrollViewDelegate (ou UITable/UICollectionViewDelegate), implémentez ceci:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
    if (scrollView.tag == SCROLLVIEW_IS_SCROLLING_TO_TOP_TAG) {
        [scrollView flashScrollIndicators];
    }
}

Le délai de masquage est un peu plus court comparé au comportement scrollToTop de la barre d'état, mais il a quand même l'air sympa.

Notez que j'abuse de la balise de vue pour communiquer l'état "isScrollingToTop" car j'en ai besoin de plusieurs contrôleurs de vue. Si vous utilisez des balises pour autre chose, vous voudrez peut-être remplacer ceci par un iVar ou une propriété.

2
Ortwin Gentz

Je pense avoir une réponse qui devrait être entièrement compatible avec iOS 11 ainsi que les versions précédentes (pour le défilement vertical)

Ceci prend en compte le nouveau adjustContentInset et explique également le décalage supplémentaire requis lorsque prefersLargeTitles est activé sur la barre de navigation, ce qui semble nécessiter un décalage supplémentaire de 52px au-dessus de la valeur par défaut. est

C’était un peu délicat, car les ajustements ajustés au contenu changeaient en fonction de l’état titleBar (gros titre vs petit titre); j’avais donc besoin de vérifier et de voir quelle était la hauteur de titleBar et de ne pas appliquer le décalage de 52px s’il était déjà dans le grand état. Impossible de trouver une autre méthode pour vérifier l'état de la barre de navigation, donc si quelqu'un a une meilleure option que de voir si la hauteur est> 44,0, j'aimerais l'entendre.

func scrollToTop(_ scrollView: UIScrollView, animated: Bool = true) {
    if #available(iOS 11.0, *) {
        let expandedBar = (navigationController?.navigationBar.frame.height ?? 64.0 > 44.0)
        let largeTitles = (navigationController?.navigationBar.prefersLargeTitles) ?? false
        let offset: CGFloat = (largeTitles && !expandedBar) ? 52: 0
        scrollView.setContentOffset(CGPoint(x: 0, y: -(scrollView.adjustedContentInset.top + offset)), animated: animated)
    } else {
        scrollView.setContentOffset(CGPoint(x: 0, y: -scrollView.contentInset.top), animated: animated)
    }
}

Inspiré par la solution de Jakub

2
user2898617

Faites défiler vers le haut pour UITableViewController, UICollectionViewController ou n’importe quel UIViewController ayant UIScrollView

extension UIViewController {

  func scrollToTop(animated: Bool) {
    if let tv = self as? UITableViewController {
        tv.tableView.setContentOffset(CGPoint.zero, animated: animated)
    } else if let cv = self as? UICollectionViewController{
        cv.collectionView?.setContentOffset(CGPoint.zero, animated: animated)
    } else {
        for v in view.subviews {
            if let sv = v as? UIScrollView {
                sv.setContentOffset(CGPoint.zero, animated: animated)
            }
        }
    }
  }
}
1
Shoaib

Il est très courant que votre barre de navigation chevauche la petite partie du contenu de scrollView et que le contenu ne commence pas du haut. Pour le réparer, j'ai fait 2 choses:

  • Inspecteur de taille - Vue de défilement - Inserts de contenu -> Passer de automatique à jamais.
  • Inspecteur de taille - Contraintes - "Aligner en haut sur" (Contraintes en haut) - Deuxième élément -> Passer de Superview.Top à Safe Area.Top et la valeur (champ constant) définie sur 0

Content insets - NeverAlign ScrolView.Top to Safe Area.Top

0
Vitya Shurapov