UITableView - przewiń w górę

392

W widoku tabeli muszę przewijać do góry. Ale nie mogę zagwarantować, że pierwszym obiektem będzie sekcja 0, wiersz 0. Może być tak, że mój widok tabeli rozpocznie się od sekcji 5.

Dostaję więc wyjątek, kiedy dzwonię:

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

Czy istnieje inny sposób przewijania do góry widoku tabeli?

Ilya Suzdalnitski
źródło

Odpowiedzi:

856

UITableView jest podklasą UIScrollView, więc możesz także użyć:

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

Lub

[mainTableView setContentOffset:CGPointZero animated:YES];

A w Swift:

mainTableView.setContentOffset(CGPointZero, animated:true)

I w Swift 3 i wyżej:

mainTableView.setContentOffset(.zero, animated: true)
catlan
źródło
9
Najpierw próbowałem tego z CGRectZero, który jest równoważny CGRectMake (0, 0, 0, 0). To nie działa, ale dziwnie powyższe działa. Chyba potrzebuje dodatniej szerokości i wysokości. Dziękuję Ci.
Keller
5
Uwaga : animacja będzie potrzebna : NIE, jeśli uruchomisz to w scrollToRowAtIndexPath: tak, aby tabela zaczęła się w prawidłowej pozycji. Mam nadzieję, że to pomoże!
Fattie
3
@ hasan83 CGRectMake (0, 0, 0, 0) lub CGRectZero nie jest widocznym odbiciem. Powiedziałbym również, że [mainTableView setContentOffset: CGPointZero animated: YES]; jest ładniejszym wyrażeniem.
catlan
8
ktoś zauważył, że w iOS11 to wszystko jest zepsute i w niektórych przypadkach nie przewija się poprawnie?
Peter Lapisu,
11
@PeterLapisu self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: UITableViewScrollPosition.top, animated: true)wydaje się działać w iOS 11
Jordan S
246

Uwaga : ta odpowiedź nie jest ważna dla iOS 11 i nowszych.

wolę

[mainTableView setContentOffset:CGPointZero animated:YES];

Jeśli masz górną wstawkę w widoku tabeli, musisz ją odjąć:

[mainTableView setContentOffset:CGPointMake(0.0f, -mainTableView.contentInset.top) animated:YES];
fabb
źródło
12
Pomidor, pomidor. Hmm ... Nie napisano tego zbyt wyraźnie na piśmie.
FreeAsInBeer
14
Jest to najlepszy sposób na użycie, gdy masz widoki nagłówka lub stopki tabeli i chcesz je również uwzględnić.
mafonya
6
To jest rzeczywiście przejrzysty kod, ale nie działa, gdy masz tableViewniezerowe contentInsetod góry. Na przykład: tableView.contentInset = UIEdgeInsetsMake(5.0f, 0.0f, 250.0f, 0.0f);. Jeśli tak jest, w kodzie tableViewprzewija się do (0.0f, 5.0f).
tolgamorf
25
Rozwiązanie mojego poprzedniego komentarza:[tableView setContentOffset:CGPointMake(0.0f, -tableView.contentInset.top) animated:YES];
tolgamorf
3
W systemie iOS 11 należy rozważyć użycie -scrollView.adjustedContentInset.topzamiast tego.
Marián Černý
79

Możliwe działania:

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

Wyłącz przewijanie do góry:

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

Zmodyfikuj i użyj go zgodnie z wymaganiami.

Szybki 4

  func scrollToFirstRow() {
    let indexPath = IndexPath(row: 0, section: 0)
    self.tableView.scrollToRow(at: indexPath, at: .top, animated: true)
  }
AG
źródło
To rozwiązanie, idealne - scrollToFirstRow
Mehul
Doskonałe podsumowanie. Jeśli masz nagłówki sekcji, będziesz musiał użyć Option4 scrollToHeader.
Vincent
Czy istnieje sposób przewinięcia w górę do paska wyszukiwania nad widokiem tabeli?
Tyler Rutt,
27

Lepiej nie używać NSIndexPath (pusta tabela), ani nie zakładać, że najwyższym punktem jest CGPointZero (wstawki zawartości), tego właśnie używam -

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

Mam nadzieję że to pomoże.

Kof
źródło
Już nie obowiązuje od iOS 11.
rmaddy
21

Swift 4 :

Działa to bardzo dobrze:

//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
źródło
3
Nie, jeśli masz tableHeaderView w tableView i jest on wbudowany (przewija się z zawartością)
finneycanhelp
1
Mam zarówno zwykły, jak i UITableViewStyleGrouped(nagłówki przewijane z zawartością) i ten kod działa. Upewnij się, że jesteś w głównym wątku i uruchamiasz ten kod po wyświetleniu widoku ( viewDidAppear). Jeśli nadal masz problemy, spróbuj umieścić kod w tym:DispatchQueue.main.asyncAfter(deadline: .now()+0.1, execute: { // the code }
Alessandro Ornano
1
Dziękuję Ci. Doprowadzi cię do pierwszej komórki. Jednak nie wyświetla nagłówka widoku tabeli.
finneycanhelp
To się nie powiedzie, jeśli tableView z jakiegoś powodu jest pusty (brak komórki w sekcji 0 w 0 rzędzie)
Maxim Skryabin
17

Wystąpił problem podczas wywoływania niektórych metod na pustym tableView. Oto kolejna opcja dla Swift 4, która obsługuje puste widoki tabeli.

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

Stosowanie:

// from yourViewController or yourTableViewController
tableView.scrollToTop(animated: true)//or false
Adrian
źródło
Nie uwzględnia to żadnego nagłówka tabeli ani nagłówka sekcji.
rmaddy
16

NIE UŻYWAJ

 tableView.setContentOffset(.zero, animated: true)

Czasami może nieprawidłowo ustawić przesunięcie. Na przykład w moim przypadku komórka znajdowała się nieco powyżej widoku z wypustkami obszaru bezpiecznego. Niedobrze.

ZAMONTUJ UŻYCIE

 tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: true)
ScottyBlades
źródło
1
Idealne rozwiązanie.
Baby Groot
Właśnie tego szukałem, dzięki.
Simon
Żadne z tych rozwiązań nie jest prawidłowe. Pierwszy nie działa w systemie iOS 11 lub nowszym. Drugi nie działa, jeśli widok tabeli ma nagłówek tabeli lub pierwsza sekcja ma nagłówek sekcji, chyba że naprawdę chcesz pierwszego wiersza na górze i nie przejmujesz się wyświetlaniem żadnych nagłówków.
rmaddy
@rmaddy jakie jest najlepsze rozwiązanie?
ScottyBlades
15

W systemie iOS 11 użyj przycisku, adjustedContentInsetaby poprawnie przewinąć do góry w obu przypadkach, gdy pasek stanu podczas połączenia jest widoczny lub nie.

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

Szybki:

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
źródło
12

Dla tabel, które mają contentInset , ustawienie przesunięcia zawartości na CGPointZeronie będzie działać. Przewinie do góry zawartości vs. do góry.

Biorąc pod uwagę zawartość wstawia to zamiast tego:

[tableView setContentOffset:CGPointMake(0, -tableView.contentInset.top) animated:NO];
Eran Goldin
źródło
1
Dziękuję, ustawiłem go na CGPointZero i nie mogłem zrozumieć, dlaczego tak się dzieje.
johnrechd
Już nie obowiązuje od iOS 11.
rmaddy
10

Ten kod pozwala przewinąć określoną sekcję do góry

CGRect cellRect = [tableinstance rectForSection:section];
CGPoint origin = [tableinstacne convertPoint:cellRect.origin 
                                    fromView:<tableistance>];
[tableinstance setContentOffset:CGPointMake(0, origin.y)];
Ramesh Muthe
źródło
To był najprostszy kod i działał OK. Właściwie umieściłem CGPointMake (0.0f, 0.0f). Twoje zdrowie!
Felipe,
Ten kod jest bardzo przydatny, aby przewinąć sekcję do góry
srinivas n
8

Szybki:

tableView.setContentOffset(CGPointZero, animated: true)
Esqarrouth
źródło
Już nie obowiązuje od iOS 11.
rmaddy
8

Szybki 3

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

gdyby tableView.setContentOffset nie działa.

Posługiwać się:

tableView.beginUpdates()
tableView.setContentOffset(CGPoint.zero, animated: true)
tableView.endUpdates()
Исмаил Хасбулатов
źródło
1
Nie dotyczy to systemu iOS 11 lub nowszego.
rmaddy
7

Ponieważ mój tableViewjest pełen wszelkiego rodzaju wypustek, była to jedyna rzecz, która działała dobrze:

Szybki 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
źródło
przydało mi się to bardziej
Tejzeratul,
świetna odpowiedź, doceń to
Jeremy Bader
7

Dodając do tego, co już powiedziano, możesz utworzyć rozszerzenie (Swift) lub kategorię (Cel C), aby ułatwić to w przyszłości:

Szybki:

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

Za każdym razem, gdy chcesz przewinąć dowolną tabelę Wyświetl na górę, możesz wywołać następujący kod:

tableView.scrollToTop(animated: true)
ocwang
źródło
2
Już nie obowiązuje od iOS 11.
rmaddy
6

Wolę następujące, ponieważ uwzględnia wstawkę. Jeśli nie ma wstawki, nadal będzie przewijana do góry, ponieważ wstawka będzie wynosić 0.

tableView.setContentOffset(CGPoint(x: 0, y: -tableView.contentInset.top), animated: true)
Jakub
źródło
Już nie obowiązuje od iOS 11.
rmaddy
5

Szybki:

jeśli nie masz nagłówka tableView:

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

jeśli tak:

tableView.setContentOffset(CGPointMake(0, -tableViewheader.frame.height   + UIApplication.sharedApplication().statusBarFrame.height ), animated: true)
jmcastel
źródło
5

Swift 5, iOS 13

Wiem, że to pytanie ma już wiele odpowiedzi, ale z mojego doświadczenia wynika, że ​​tylko jedna metoda zawsze działa:

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

Jeśli pracujesz w trybie asynchronicznym, tabele animowane za pomocą klawiatury itp., Inne odpowiedzi często przewijają się do prawie do dołu, a nie do absolutnego dołu. Ta metoda za każdym razem doprowadzi cię do absolutnego końca tabeli.

bsod
źródło
Musisz także sprawdzić, czy jest sekcja
Tuńczyk Onur
4

Oto, czego używam do prawidłowego działania w systemie 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
źródło
4

W Swift 5 bardzo dziękuję za odpowiedź Adriana

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

}

Stosowanie:

tableView.scrollToTop()
dengST30
źródło
2
1. Dotyczy to również Swift 4. 2. To nie działa, jeśli istnieje nagłówek tabeli lub nagłówek sekcji.
rmaddy
3

Korzystanie z contentOffset nie jest właściwą drogą. byłoby to lepsze, ponieważ jest to naturalny sposób widoku tabeli

tableView.scrollToRow(at: NSIndexPath.init(row: 0, section: 0) as IndexPath, at: .top, animated: true)
Gulz
źródło
2
To nie zadziała, jeśli istnieje nagłówek tabeli lub nagłówek sekcji.
rmaddy
3

To był jedyny fragment kodu, który działał dla mnie

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 to wysokość mojej komórki widoku nagłówka i tabeli

jimmyruby
źródło
Jest to dalekie od prawidłowego sposobu przewijania na górę. Nie ma sensu używać trzech oddzielnych linii tylko do ustawienia przesunięcia zawartości. Potrzebny jest tylko ostatni wiersz, ale kodowanie określonego przesunięcia nie jest poprawnym rozwiązaniem.
rmaddy
2
func scrollToTop() {
        NSIndexPath *topItem = [NSIndexPath indexPathForItem:0 inSection:0];
        [tableView scrollToRowAtIndexPath:topItem atScrollPosition:UITableViewScrollPositionTop animated:YES];
}

wywołać tę funkcję, gdziekolwiek chcesz UITableView przewiń do góry

Sayali Shinde
źródło
2

Swift 4 przez rozszerzenie, obsługuje widok pustej tabeli:

extension UITableView {
    func scrollToTop(animated: Bool) {
        self.setContentOffset(CGPoint.zero, animated: animated);
    }
}
Shawn
źródło
Nie dotyczy to iOS 11.
rmaddy
2

Używam tabBarController i mam kilka sekcji w widoku tabeli na każdej karcie, więc jest to dla mnie najlepsze rozwiązanie.

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
źródło
1

Musiałem dodać pomnożenie -1 *do sumy paska stanu i paska nawigacji, ponieważ schodziła o tę wysokość z ekranu,

self.tableView.setContentOffset(CGPointMake(0 , -1 * 
  (self.navigationController!.navigationBar.height +  
  UIApplication.sharedApplication().statusBarFrame.height) ), animated:true)
Carlos.V
źródło
1

w szybkim tempie

Twój wiersz = selectioncellRowNumber twoja sekcja jeśli masz = selectionNumber jeśli nie masz ustawionego, to zero

//UITableViewScrollPosition.Middle lub Bottom or Top

var lastIndex = NSIndexPath(forRow:  selectioncellRowNumber, inSection: selectionNumber)
self.tableView.scrollToRowAtIndexPath(lastIndex, atScrollPosition: UITableViewScrollPosition.Middle, animated: true)
idris yıldız
źródło
1

Oto kod do przewijania ScrollTableView do góry Programowo

Szybki:

self.TableView.setContentOffset(CGPointMake(0, 1), animated:true)
Kavin Kumar Arumugam
źródło
1

W Swift-3:

self.tableView.setContentOffset(CGPoint.zero, animated: true)
Jeni Khant
źródło
0

Jeśli chcesz przenieść animację przewijania w tabeli, użyj tego kodu. Przewiń do góry z animacją za 0,5 sekundy.

[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
źródło
0

Z Swift:

self.scripSearchView.quickListTbl?.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
Dhananjay Patil
źródło