Pobierz UIScrollView, aby przewinąć do góry

Odpowiedzi:

316

AKTUALIZACJA DLA iOS 7

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

ORYGINALNY

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

lub jeśli chcesz zachować poziomą pozycję przewijania i po prostu zresetować pozycję pionową:

[self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, 0)
    animated:YES];
rob mayoff
źródło
50
Jeśli robisz to na iOS 7, być może będziesz musiał wziąć pod uwagę UIScrollView contentInsetniestety. [self.scrollView setContentOffset:CGPointMake(self.scrollView.contentOffset.x, -self.scrollView.contentInset.top) animated:YES];robi robotę za mnie
runmad
11
Udało mi się przewinąć do góry, tuż pod paskiem nawigacji i stanu. [scrollView setContentOffset:CGPointMake(0, -scrollView.contentInset.top) animated:YES];Działa na iOS 6 i 7
Amozoss,
To nie zadziałało, prawdopodobnie dlatego, że robię coś szalonego z odwróconym widokiem w zestawie duszków. Ale jeśli ktoś inny jest tak szalony jak ja - a twój widok przewijania jest domyślnie na dole - to przewinie go do góry:[scrollView setContentOffset:CGPointMake(0, scrollView.contentSize.height-scrollView.frame.size.height) animated:YES];
GilesDMiddleton
Komentarz z ostatniej chwili: powinieneś dostosować się do wstawki zawartości niezależnie od wersji systemu operacyjnego. iOS 7 używa go do zezwalania na przewijanie zawartości poniżej paska stanu, ale zawsze był on eksponowany jako właściwość, więc zawsze był potencjalnie używany przez kogoś.
Tommy,
2
W przypadku iOS 11+ pomocna, przynajmniej w moim przypadku, była poniższa odpowiedź Jakuba Truhlářa z użyciem adjustContentInset.
tv
61

Oto rozszerzenie Swift, które to ułatwia:

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

Stosowanie:

myScrollView.scrollToTop()
Andrew Schreiber
źródło
40

iOS 11 i nowsze

spróbuj pracować z nowym adjustedContentInset.

Na przykład (przewiń do góry):

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)

Nawet jeśli używasz prefersLargeTitles, safe areaetc.

Jakub Truhlář
źródło
40

Dla Swift 4

scrollView.setContentOffset(.zero, animated: true)
Rajasekhar Pasupuleti
źródło
23

Posługiwać się setContentOffset:animated:

[scrollView setContentOffset:CGPointZero animated:YES];
Bryan Chen
źródło
17

Odpowiedź dla Swift 2.0 / 3.0 / 4.0 i iOS 7+:

let desiredOffset = CGPoint(x: 0, y: -self.scrollView.contentInset.top)
self.scrollView.setContentOffset(desiredOffset, animated: true)
warto
źródło
8

W iOS7 miałem problem z uzyskaniem określonego widoku przewijania na górę, który działał w iOS6, i użyłem tego do ustawienia widoku przewijania na górę.

[self.myScroller scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
hoak
źródło
Mam ten sam problem w iOS7. Czy ktoś wie, jak włączyć to dla UITableView?
DZenBot
1
To zabawne, jak to działa, gdy animacja jest NIE, ale nie, gdy animacja jest TAK. Jeśli TAK, to przewija się prawie do topdevgm16
Matt Becker
4

Odpowiedź Roba Mayoffa w Swift 3.0.1 :

self.scrollView.setContentOffset(
CGPoint(x: 0,y: -self.scrollView.contentInset.top),
animated: true)
Roni Leshes
źródło
2

Aby w pełni odtworzyć zachowanie scrollToTop paska stanu, musimy nie tylko ustawić contentOffset, ale także upewnić się, że wskaźniki scrollIndicators są wyświetlane. W przeciwnym razie użytkownik może szybko się zgubić.

Jedyną publiczną metodą osiągnięcia tego jest flashScrollIndicators. Niestety, wywołanie go raz po ustawieniu contentOffset nie daje żadnego efektu, ponieważ jest resetowane natychmiast. Zauważyłem, że działa, gdy wykonuję flashowanie za każdym razem w 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;
    });
}

W swoim UIScrollViewDelegate (lub UITable / UICollectionViewDelegate) zaimplementuj to:

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

Opóźnienie ukrywania jest nieco krótsze w porównaniu do zachowania scrollToTop paska stanu, ale nadal wygląda ładnie.

Zauważ, że nadużywam tagu widoku do komunikowania stanu „isScrollingToTop”, ponieważ potrzebuję tego między kontrolerami widoku. Jeśli używasz tagów do czegoś innego, możesz zamienić to na iVar lub właściwość.

Ortwin Gentz
źródło
Nie testowałem, ale powinno to rzucić to w następnym runloopie, jeśli zamiast tego użyjesz DISPATCH_TIME_NOW. Dziękuję za wykonanie tej pracy, nie jestem pewien, czy jeszcze tego potrzebuję, ale dobrze wiedzieć.
Dan Rosenstark
To było jakiś czas temu i nie pamiętam dokładnie, ale wydaje mi się, że to nie zadziałało. Odroczenie do następnego runloopa jest zwykle pierwszą rzeczą, której próbuję w takich przypadkach.
Ortwin Gentz
2

Myślę, że mam odpowiedź, która powinna być w pełni kompatybilna z iOS 11, a także wcześniejszymi wersjami (do przewijania w pionie)

Uwzględnia to nowy dostosowany zestaw treści, a także dodatkowe przesunięcie wymagane, gdy preferowane są duże tytuły jest włączona navigationBar który wydaje się wymagać dodatkowego 52px offsetowy na szczycie, co domyślnie jest

Było to trochę trudne, ponieważ dostosowanyContentInset zmienia się w zależności od stanu titleBar (duży tytuł vs mały tytuł), więc musiałem sprawdzić i zobaczyć, jaka była wysokość titleBar i nie zastosować przesunięcia 52px, jeśli jest już w stanie dużym. Nie mogłem znaleźć innej metody sprawdzenia stanu paska nawigacji, więc jeśli ktoś ma lepszą opcję niż sprawdzenie, czy wysokość jest> 44,0, chciałbym to usłyszeć

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

Zainspirowany rozwiązaniem Jakuba

user2898617
źródło
2

Jest to bardzo powszechne, gdy pasek nawigacji nakłada się na małą część zawartości scrollView i wygląda na to, że treść nie zaczyna się od góry. Aby to naprawić, zrobiłem 2 rzeczy:

  • Inspektor rozmiaru - Widok przewijania - Wstawki zawartości -> Zmień z automatycznego na Nigdy.
  • Inspektor rozmiaru - Ograniczenia - „Wyrównaj górę do” (Ograniczenia wyrównania do góry) - Drugi element -> Zmień z Superview.Top na Bezpieczny obszar.Top i wartość (pole stałe) ustawiona na 0

Wstawki z treścią - nigdy Wyrównaj ScrolView.Top do Safe Area.Top

Vitya Shurapov
źródło
1

Przewiń do góry za UITableViewController, UICollectionViewControllerlub dowolny UIViewControllerkoniecznościUIScrollView

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)
            }
        }
    }
  }
}
Shoaib
źródło
0

W SWIFT 5 Po prostu ustaw wartość Offset na zero

scrollView.setContentOffset(CGPoint.zero, animated: true)
Abdul Karim Khan
źródło
-4

Próbowałem wszystkich sposobów. Ale dla mnie nic nie działało. Wreszcie mi się to podobało.

Dodałem self.view .addSubview(self.scroll)linię kodu w viewDidLoad. Po rozpoczęciu konfigurowania ramki dla widoku przewijania i dodaniu komponentów do widoku przewijania.

U mnie to zadziałało.

Upewnij się, że dodałeś self.view .addSubview(self.scroll)linię na początku. następnie możesz dodać elementy interfejsu użytkownika.

Narasimha Nallamsetty
źródło
Usuń to. Chociaż z pewnością miało to sens w tamtym czasie, twoje problemy z hierarchią podglądów podrzędnych nie są istotne dla tego pytania.
Dan Rosenstark
1
@Cristik, jeśli widok przewijania nie znajduje się w hierarchii widoków lub komputer jest wyłączony, oczywiście nic z tego nie zadziała. Ale OP zapytał o coś dość wąskiego
Dan Rosenstark