Lassen Sie UIScrollView nach oben scrollen


Antworten:


316

UPDATE FÜR iOS 7

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

ORIGINAL

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

oder wenn Sie die horizontale Bildlaufposition beibehalten und einfach die vertikale Position zurücksetzen möchten:

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

50
Wenn Sie dies für iOS 7 tun, müssen Sie dies möglicherweise UIScrollView contentInsetleider berücksichtigen . [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];macht den Job für mich
runmad

11
Ich konnte nach oben scrollen, direkt unter der Navigations- und Statusleiste. [scrollView setContentOffset:CGPointMake(0, -scrollView.contentInset.top) animated:YES];Es funktioniert in iOS 6 & 7
Amozoss

Das hat bei mir nicht funktioniert, wahrscheinlich weil ich etwas Verrücktes mit einer umgekehrten Ansicht im Sprite-Kit mache. Aber wenn jemand so verrückt ist wie ich - und Ihre Bildlaufansicht standardmäßig unten ist - wird dies nach oben [scrollView setContentOffset:CGPointMake(0, scrollView.contentSize.height-scrollView.frame.size.height) animated:YES];
gescrollt

Late-in-the-Day-Kommentar: Sie sollten den Inhalt unabhängig von der Betriebssystemversion anpassen. iOS 7 verwendet es zufällig, um Bildlaufinhalte unterhalb der Statusleiste zuzulassen, aber es wurde immer als Eigenschaft angezeigt und wurde daher möglicherweise immer von jemandem verwendet.
Tommy

2
Für iOS 11+ war die Antwort von Jakub Truhlář unten mit adjustContentInset hilfreich, zumindest in meinem Fall.
tnev

61

Hier ist eine Swift-Erweiterung, die es einfach macht:

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

Verwendung:

myScrollView.scrollToTop()

40

iOS 11 und höher

versuche mit dem neuen zu arbeiten adjustedContentInset.

Zum Beispiel (nach oben scrollen):

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)

Auch wenn Sie verwenden prefersLargeTitles, safe areaetc.



23

Verwenden setContentOffset:animated:

[scrollView setContentOffset:CGPointZero animated:YES];

17

Antwort für Swift 2.0 / 3.0 / 4.0 und iOS 7+:

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

8

In iOS7 hatte ich Probleme, eine bestimmte Bildlaufansicht nach oben zu bringen, was in iOS6 funktionierte, und habe damit die Bildlaufansicht so eingestellt, dass sie nach oben zeigt.

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

Ich habe das gleiche Problem in iOS7. Weiß jemand, wie man dies für eine UITableView aktiviert?
DZenBot

1
Es ist lustig, wie das funktioniert, wenn animiert NEIN ist, aber nicht, wenn animiert JA ist. Wenn JA, dann scrollt es fast zum topdevgm16
Matt Becker


2

Um das scrollToTop-Verhalten der Statusleiste vollständig zu replizieren, müssen wir nicht nur das contentOffset festlegen, sondern auch sicherstellen, dass die scrollIndicators angezeigt werden. Andernfalls kann der Benutzer schnell verloren gehen.

Die einzige öffentliche Methode, um dies zu erreichen, ist flashScrollIndicators. Leider hat das einmalige Aufrufen nach dem Festlegen von contentOffset keine Auswirkung, da es sofort zurückgesetzt wird. Ich fand, dass es funktioniert, wenn ich jedes Mal den Blitz mache 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;
    });
}

Implementieren Sie in Ihrem UIScrollViewDelegate (oder UITable / UICollectionViewDelegate) Folgendes:

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

Die Ausblendverzögerung ist etwas kürzer als das ScrollToTop-Verhalten in der Statusleiste, sieht aber trotzdem gut aus.

Beachten Sie, dass ich das Ansichtstag verwende, um den Status "isScrollingToTop" zu kommunizieren, da ich dies über Ansichtscontroller hinweg benötige. Wenn Sie Tags für etwas anderes verwenden, möchten Sie diese möglicherweise durch ein iVar oder eine Eigenschaft ersetzen.


Ich habe es nicht getestet, aber es sollte dies beim nächsten Runloop auslösen, wenn Sie stattdessen nur DISPATCH_TIME_NOW verwenden. Vielen Dank für diese Arbeit, ich bin mir nicht sicher, ob ich sie noch brauche, aber gut zu wissen.
Dan Rosenstark

Es ist eine Weile her und ich erinnere mich nicht genau, aber ich glaube, das hat nicht funktioniert. In solchen Fällen ist es normalerweise das erste, was ich versuche, auf den nächsten Runloop zu verschieben.
Ortwin Gentz

2

Ich denke, ich habe eine Antwort, die sowohl mit iOS 11 als auch mit früheren Versionen (für vertikales Scrollen) vollständig kompatibel sein sollte.

Dies berücksichtigt das neue AdjustedContentInset und berücksichtigt auch den zusätzlichen Offset, der erforderlich ist, wenn PreferLargeTitles bevorzugt wird in der Navigationsleiste ist. scheint einen zusätzlichen Versatz von 52 Pixel zusätzlich zu den Standardeinstellungen zu erfordern

Dies war etwas knifflig, da sich das angepasste ContentInset abhängig vom titleBar-Status (großer Titel vs. kleiner Titel) ändert. Daher musste ich überprüfen, wie hoch die titleBar-Höhe war, und den 52px-Offset nicht anwenden, wenn er sich bereits im großen Status befindet. Es konnte keine andere Methode gefunden werden, um den Status der Navigationsleiste zu überprüfen. Wenn also jemand eine bessere Option hat, als zu sehen, ob die Höhe> 44,0 ist, würde ich sie gerne hören

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

Inspiriert von Jakubs Lösung


2

Es ist sehr häufig, wenn Ihre Navigationsleiste den kleinen Teil des scrollView-Inhalts überlappt und es so aussieht, als würde der Inhalt nicht von oben beginnen. Um das Problem zu beheben, habe ich zwei Dinge getan:

  • Größeninspektor - Bildlaufansicht - Inhaltseinfügungen -> Wechsel von Automatisch zu Nie.
  • Größeninspektor - Einschränkungen - "Oben ausrichten an" (Einschränkungen für die obere Ausrichtung) - Zweites Element -> Von Superview.Top zu Safe Area.Top wechseln und der Wert (konstantes Feld) auf 0 setzen

Inhaltseinfügungen - Niemals Richten Sie ScrolView.Top an Safe Area.Top aus


1

Nach oben scrollen für UITableViewController, UICollectionViewControlleroder jeder UIViewControllermitUIScrollView

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

0

In SWIFT 5 Setzen Sie einfach den Inhaltsversatz auf Null

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

-4

Ich habe alle Möglichkeiten ausprobiert. Aber nichts hat bei mir funktioniert. Endlich hat mir das gefallen.

Ich habe eine self.view .addSubview(self.scroll)Codezeile in viewDidLoad hinzugefügt. Nach dem Einrichten des Rahmens für die Bildlaufansicht und dem Hinzufügen von Komponenten zur Bildlaufansicht.

Es hat bei mir funktioniert.

Stellen Sie sicher, dass Sie self.view .addSubview(self.scroll)am Anfang eine Zeile hinzugefügt haben . Dann können Sie UI-Elemente hinzufügen.


Bitte löschen Sie dies. Während es zu dieser Zeit sicherlich Sinn machte, sind Ihre Probleme mit der Subview-Hierarchie für diese Frage nicht relevant.
Dan Rosenstark

1
@Cristik Wenn Ihre Bildlaufansicht nicht in der Ansichtshierarchie enthalten ist oder Ihr Computer ausgeschaltet ist, funktioniert dies natürlich nicht. Aber das OP fragte etwas ziemlich Enges
Dan Rosenstark
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.