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?

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)

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];

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

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.


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)

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

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)

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

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];

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)];

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

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

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)

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)

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)

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.


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

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

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)

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


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


2

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

extension UITableView {
    func scrollToTop(animated: Bool) {
        self.setContentOffset(CGPoint.zero, animated: animated);
    }
}

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

    }

}

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)

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)

1

Oto kod do przewijania ScrollTableView do góry Programowo

Szybki:

self.TableView.setContentOffset(CGPointMake(0, 1), animated:true)


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];

0

Z Swift:

self.scripSearchView.quickListTbl?.scrollToRowAtIndexPath(indexPath, atScrollPosition: .Top, animated: true)
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.