Zmień domyślne zachowanie przewijania nagłówka sekcji UITableView

147

Mam UITableView z dwiema sekcjami. To jest prosty widok tabeli. Używam viewForHeaderInSection do tworzenia niestandardowych widoków dla tych nagłówków. Na razie w porządku.

Domyślne zachowanie przewijania polega na tym, że po napotkaniu sekcji nagłówek sekcji pozostaje zakotwiczony poniżej paska nawigacji, dopóki następna sekcja nie zostanie przewinięta do widoku.

Moje pytanie brzmi: czy mogę zmienić domyślne zachowanie, tak aby nagłówki sekcji NIE były zakotwiczone u góry, ale raczej przewijały się pod paskiem nawigacji wraz z pozostałymi wierszami sekcji?

Czy brakuje mi czegoś oczywistego?

Dzięki.

davidjhinson
źródło
1
To musi być jedno z najlepiej napisanych pytań na tej stronie! :) Dzięki.
Fattie
1
Sprawdź tutaj, jak osiągnąć ten efekt stackoverflow.com/a/13735238/1880899
Sumit Anantwar

Odpowiedzi:

175

Sposób, w jaki rozwiązałem ten problem, to wyregulowanie contentOffsetzgodnie contentInsetz UITableViewControllerDelegate(rozszerza UIScrollViewDelegate) w następujący sposób:

- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
       CGFloat sectionHeaderHeight = 40;
   if (scrollView.contentOffset.y<=sectionHeaderHeight&&scrollView.contentOffset.y>=0) {
       scrollView.contentInset = UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0);
   } else if (scrollView.contentOffset.y>=sectionHeaderHeight) {
       scrollView.contentInset = UIEdgeInsetsMake(-sectionHeaderHeight, 0, 0, 0);
   }
}

Jedynym problemem jest to, że traci trochę odbicia podczas przewijania do góry.


{UWAGA: „40” powinno być dokładną wysokością nagłówka TWOJEJ sekcji 0. Jeśli użyjesz liczby większej niż wysokość nagłówka sekcji 0, zobaczysz, że ma to wpływ na dotyk (spróbuj na przykład „1000”, a zobaczysz, że zachowanie odbijania jest trochę dziwne na górze). jeśli liczba odpowiada wysokości nagłówka sekcji 0, dotyk palca wydaje się być doskonały lub prawie doskonały.}

awulf
źródło
1
Idealne rozwiązanie niż powyższe.
prathumca
4
Dziękuję Ci! To doskonałe rozwiązanie. Czy masz rozwiązanie dla stopki sekcji?
Tuan Nguyen
12
To rozwiązanie nie obsługuje poprawnie paska menu dotknięcia, który powinien przewijać na górę listy.
Reid Ellis
jeśli potrzebujesz tego samego zachowania dla widoku stopki sekcji, po prostu zmień ostatnią linię w ten sposób: scrollView.contentInset = UIEdgeInsetsMake (0, 0, sectionHeaderHeight, 0)
alex
To wydaje się wystarczające: scrollView.contentInset = UIEdgeInsetsMake (scrollView.contentOffset.y> = 0? -ScrollView.contentOffset.y: 0, 0, 0, 0);
MacMark
85

Możesz także dodać sekcję z zerową liczbą wierszy na górze i po prostu użyć stopki poprzedniej sekcji jako nagłówka następnej.

voidStern
źródło
13
W moim przypadku, gdy mam więcej niż 2 sekcje, stopka zakotwiczy na dole ..
Joseph Lin
3
Jest to kreatywne, ale musisz dostosować indexPath, jeśli używasz NSFetchedResultsController do ładowania tabeli.
XJones,
+1 zdecydowanie NAJLEPSZE rozwiązanie - wdrożenie zajęło mi około 3 linii!
Jon
Brilliant Brilliant Brilliant :-)
iphonic
Jak to zadziała w przypadku stopki, która zakotwicza? Byłbym wdzięczny za pomoc! Dzięki
darwindeeds
36

Gdybym to robił, wykorzystałbym fakt, że UITableViews w stylu Plain mają lepkie nagłówki, a te w stylu zgrupowanym nie. Prawdopodobnie przynajmniej spróbowałbym użyć niestandardowej komórki tabeli, aby naśladować wygląd zwykłych komórek w zgrupowanej tabeli.

Właściwie tego nie próbowałem, więc może to nie zadziałać, ale radziłbym to zrobić.

Colin Barrett
źródło
Prawdopodobnie zadziała, ale czy próbowano? Wydaje się, że to dużo pracy, gdy odpowiedź @ voidStern działa idealnie !!
Bentford
Odpowiedź voidStern nie działa dla mnie, gdy mam więcej niż dwie sekcje. Odpowiedź Colina jest prostsza / bardziej elegancka, bez konieczności ręcznego przesuwania numeru sekcji i dodawania liczby sekcji.
Joseph Lin
Wskazówki: użyj, tableView.separatorColor = [UIColor clearColor];aby naśladować zwykły widok tabeli.
Joseph Lin
3
Próbowałem to zrobić, ale kiedy nie mogłem sprawić, by zgrupowane komórki tabeli wyglądały jak zwykłe, tj. Usuń lewy i prawy margines po obu stronach komórek. Jak to zrobiłeś?
Adam Carter
1
Wielkie dzięki za wyjaśnienie rzeczy na temat UITableViewStyle, tj. Zgrupowanych i zwykłych, które decydują, czy nagłówek / stopka sekcji widoku tabeli będzie przyklejony, czy nie. Wielkie dzięki @Colin Barrett
Dhaval H. Nena
28

Wiem, że przychodzi późno, ale znalazłem ostateczne rozwiązanie!

Jeśli masz 10 sekcji, pozwól, aby źródło danych zwróciło 20. Użyj liczb parzystych jako nagłówków sekcji i liczb nieparzystych do zawartości sekcji. coś takiego

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section%2 == 0) {
        return 0;
    }else {
        return 5;
    }
}

-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (section%2 == 0) {
        return [NSString stringWithFormat:@"%i", section+1];
    }else {
        return nil;
    }
}

Voilá! :RE

LocoMike
źródło
świetny pomysł. ale jeśli masz tytuły indeksu sekcji, podejrzewam, że to je zepsuje.
roocell
czemu? możesz zrobić to samo z tytułami sekcji. Po prostu zapamiętaj zero dla liczb nieparzystych i tytuł dla liczby parzystej.
LocoMike
1
tak - ta metoda działa świetnie. To było dużo księgowości (prawdopodobnie związane ze sposobem, w jaki muszę zdobyć tytuły sekcji), ale zadziałało. Sztuczka polega na tym, że numberOfRowsInSection i cellForRowAtIndexPath używają if (section% 2! = 0 && section! = 0), podczas gdy titleForHeaderInSection i inne funkcje indeksu sekcji używają if (section% 2 == 0)
roocell
autor powinien wybrać tę odpowiedź jako odpowiedź. Byłoby wspaniale, gdyby istniał sposób na podklasę uitableview, aby automatycznie zakotwiczać tytuły sekcji.
roocell
To zadziałało najlepiej dla mnie. Najpierw wypróbowałem rozwiązanie @ Colin, ale nie działało dobrze z mocno dostosowanym UITableView, którego używam.
kubi
15

Jest kilka rzeczy, które należy zrobić, aby rozwiązać ten problem w niehackerski sposób:

  1. Ustaw styl widoku tabeli na UITableViewStyleGrouped
  2. Ustaw widok tabeli backgroundColorna[UIColor clearColor]
  3. Ustaw backgroundVieww każdej komórce widoku tabeli pusty widok za pomocąbackgroundColor [UIColor clearColor]
  4. W razie potrzeby odpowiednio ustaw widok tabeli rowHeightlub nadpisz, tableView:heightForRowAtIndexPath:jeśli poszczególne wiersze mają różne wysokości.
Neil Gall
źródło
(+1) @Neil, wypróbowałem twoją odpowiedź, ale niestety UITableViewStyleGroupedkomórki tabeli mają dodatkowe marginesy, które zmieniają ich wyrównanie z nagłówkiem. Jest to problem, gdy faktycznie chcesz przedstawić tabelę wielokolumnową i użyć nagłówka do pokazania tytułów kolumn (a następnie wyrównać poszczególne wpisy tabeli z tymi tytułami).
brainjam,
15

Pierwotnie opublikowane Tutaj , szybkie rozwiązanie z wykorzystaniem IB. To samo można zrobić programowo, choć po prostu.

Prawdopodobnie łatwiejszy sposób na osiągnięcie tego (za pomocą IB):

Przeciągnij UIView do TableView, aby ustawić go jako widok nagłówka.

  1. Ustaw wysokość widoku nagłówka na 100 pikseli
  2. Ustaw wartość tableview contentInset (top) na -100
  3. Nagłówki sekcji będą teraz przewijać się jak każda zwykła komórka.

Niektórzy komentowali, że to rozwiązanie ukrywa pierwszy nagłówek, jednak nie zauważyłem takiego problemu. U mnie zadziałało idealnie i było zdecydowanie najprostszym rozwiązaniem, jakie do tej pory widziałem.

Doc
źródło
Zwróć uwagę, że prawdopodobnie powinieneś ustawić widok tak, aby używał tła w kolorze Clearcolor, w przeciwnym razie, jeśli przewiniesz poza górę, zobaczysz biały na odbiciu.
Doc
3
Ukrywa mój pierwszy nagłówek
Leena,
Leena, na jakiej wersji iOS używasz? Czy widok jest UITableViewController lub UIView z UITableView w nim? Nie jestem pewien, dlaczego dla niektórych takie rozwiązanie ukrywa pierwszy nagłówek, więc staram się znaleźć jakieś rozbieżności.
Doc,
To rozwiązanie jest doskonałe. Szukam nieskończonego wyglądu tła górnej i dolnej komórki - to całkowicie to spełnia. Miły!
Taylor Halliday,
To rozwiązanie jest doskonałe. Łatwiejsze do wykonania niż inne odpowiedzi w tym wątku. Moim zdaniem powinna to być akceptowana odpowiedź.
John Rogers
15

Nie podobały mi się dotychczas opisane tutaj rozwiązania, więc starałem się je łączyć. Rezultatem jest następujący kod, zainspirowany @awulf i @cescofry. U mnie to działa, ponieważ nie mam prawdziwego nagłówka widoku tabeli. Jeśli masz już nagłówek widoku tabeli, może być konieczne dostosowanie wysokości.

// Set the edge inset
self.tableView.contentInset = UIEdgeInsetsMake(-23.0f, 0, 0, 0);

// Add a transparent UIView with the height of the section header (ARC enabled)
[self.tableView setTableHeaderView:[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 100.0f, 23.0f)]];
Thomas Kekeisen
źródło
To było najprostsze rozwiązanie, jakie znalazłem.
Zorayr
To zadziałało dla mnie na iOS9.2, więc mimo że starsza odpowiedź jest nadal ważna. I nie ukrył nagłówka pierwszej sekcji. Działa i działa idealnie.
idStar
Idealny. Jeśli widok tabeli ma już nagłówek, po prostu zwiększ jego wysokość o przesunięcie, a następnie zwiększ stałą górną zawartość nagłówka, aby przesunąć zawartość w dół do pierwotnej pozycji
Jason
14

Po prostu zmień styl TableView:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

Dokumentacja UITableViewStyle :

UITableViewStylePlain - zwykły widok tabeli. Wszelkie nagłówki lub stopki sekcji są wyświetlane jako separatory w wierszu i przesuwają się podczas przewijania widoku tabeli.

UITableViewStyleGrouped - widok tabeli, którego sekcje przedstawiają różne grupy wierszy. Nagłówki i stopki sekcji nie są ruchome.

Arthur S.
źródło
świetna odpowiedź, zadziałała dla mnie. nie ma potrzeby żadnego obejścia
Shams Ahmed
9

Wybierz styl zgrupowany TableView

Wybierz styl zgrupowanego widoku tabeli z inspektora atrybutów tableView w scenorysie.

Arjun Shukla
źródło
5

Ustaw headerView tabeli z przezroczystym widokiem z tą samą wysokością nagłówka w widoku przekroju. Zainicjuj także widok tabeli z ramką na wysokości.

self.tableview = [[UITableView alloc] initWithFrame:CGRectMake(0, - height, 300, 400)];

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, width, height)] autorelease];
[self.tableView setTableHeaderView:headerView];
cescofry
źródło
4

Znalazłem alternatywne rozwiązanie, użyj pierwszej komórki każdej sekcji zamiast prawdziwej sekcji nagłówka, to rozwiązanie nie wygląda tak czysto, ale działa tak dobrze, że możesz użyć zdefiniowanej komórki prototypowej dla sekcji nagłówków oraz w metodzie cellForRowAtIndexPath zapytaj o indexPath.row == 0, jeśli prawda, użyj komórki prototypowej sekcji nagłówka, w przeciwnym razie użyj domyślnej komórki prototypowej.

AlexBB
źródło
Jeśli nadal chcesz pracować z indexPath.row& indexPath.section, upewnij się, że zwracasz wysokość 0.0ffor, - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectionaby nagłówki były niewidoczne.
Zupa
4

Zmień styl TableView:

self.tableview = [[UITableView alloc] initwithFrame:frame style:UITableViewStyleGrouped];

Zgodnie z dokumentacją Apple dla UITableView:

UITableViewStylePlain - zwykły widok tabeli. Wszelkie nagłówki lub stopki sekcji są wyświetlane jako separatory w wierszu i przesuwają się podczas przewijania widoku tabeli.

UITableViewStyleGrouped - widok tabeli, którego sekcje przedstawiają różne grupy wierszy. Nagłówki i stopki sekcji nie są ruchome. Mam nadzieję, że ta mała zmiana Ci pomoże ...

Aks
źródło
2

Teraz, gdy zgrupowany styl wygląda w zasadzie tak samo jak zwykły styl w iOS 7 (pod względem płaskości i tła), dla nas najlepszą i najłatwiejszą (tj. Najmniej hakerską) poprawką była po prostu zmiana stylu widoku tabeli na zgrupowany. Jacking z contentInsets zawsze stanowił problem, gdy zintegrowaliśmy pasek nawigacji z przewijaniem na górze. Ze zgrupowanym stylem widoku tabeli wygląda dokładnie tak samo (z naszymi komórkami), a nagłówki sekcji pozostają niezmienione. Bez przewijania dziwności.

Greg Combs
źródło
Jest to najlepsze rozwiązanie, zwłaszcza jeśli komórki są niestandardowe. Wydaje się, że po prostu zatrzymuje „wstrzymanie” nagłówka sekcji, gdy przewijanie dotrze do góry.
Recycled Steel
1

Przypisz ujemną wstawkę do swojego tableView. Jeśli masz nagłówki sekcji o wysokości 22 pikseli i nie chcesz, aby były lepkie, zaraz po ponownym załadowaniu danych dodaj:

self.tableView.contentInset = UIEdgeInsetsMake(-22, 0, 0, 0); 
self.tableView.contentSize = CGSizeMake(self.tableView.contentSize.width, self.tableView.contentSize.height+22); 

U mnie działa jak urok. Działa również dla stopek sekcji, zamiast tego przypisz ujemną wstawkę na dole.

Mike A.
źródło
To tylko odcina pierwszy nagłówek?
cannyboy
Pracował dla mnie idealnie !! Dzięki
Daniel,
0

Dodaję tabelę do widoku przewijania i wydaje się, że działa dobrze.

Dolbex
źródło
0

Sprawdź moją odpowiedź tutaj . Jest to najłatwiejszy sposób na zaimplementowanie niepływających nagłówków sekcji bez żadnych hacków.

Sumit Anantwar
źródło
0

Odpowiedź @ LocoMike najlepiej pasowała do mojego tableView, jednak zepsuła się również podczas używania stopek. To jest poprawione rozwiązanie w przypadku używania nagłówków i stopek:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return (self.sections.count + 1) * 3;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    if (section % 3 != 1) {
        return 0;
    }
    section = section / 3;
    ...
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return 0;
    }
    section = section / 3;
    ...
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return 0;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
    if (section % 3 != 0) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section
{
    if (section % 3 != 2) {
        return nil;
    }
    section = section / 3;
    ...
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    int section = indexPath.section;
    section = section / 3;
    ...
}
marmor
źródło
0

Szybka wersja odpowiedzi @awulf, która działa świetnie!

func scrollViewDidScroll(scrollView: UIScrollView) {
    let sectionHeight: CGFloat = 80
    if scrollView.contentOffset.y <= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake( -scrollView.contentOffset.y, 0, 0, 0)
    }else if scrollView.contentOffset.y >= sectionHeight {
        scrollView.contentInset = UIEdgeInsetsMake(-sectionHeight, 0, 0, 0)
    }
}
Jeff
źródło
-2

Dowiedziałem się, że wystarczy ustawienie właściwości tableHeaderView, czyli:

 tableView.tableHeaderView = customView;

i to wszystko.

Soni
źródło