Ändern Sie das Standard-Bildlaufverhalten des UITableView-Abschnittskopfs

147

Ich habe eine UITableView mit zwei Abschnitten. Es ist eine einfache Tabellenansicht. Ich verwende viewForHeaderInSection, um benutzerdefinierte Ansichten für diese Header zu erstellen. So weit, ist es gut.

Das Standard-Bildlaufverhalten besteht darin, dass bei Auftreten eines Abschnitts die Abschnittsüberschrift unter der Navigationsleiste verankert bleibt, bis der nächste Abschnitt in die Ansicht gescrollt wird.

Meine Frage lautet: Kann ich das Standardverhalten so ändern, dass die Abschnittsüberschriften NICHT oben verankert bleiben, sondern mit den restlichen Abschnittszeilen unter der Navigationsleiste scrollen?

Vermisse ich etwas Offensichtliches?

Vielen Dank.

Davidjhinson
quelle
1
Das muss eine der am besten geschriebenen Fragen auf dieser Seite sein! :) Vielen Dank.
Fattie
1
Suchen
Sumit Anantwar

Antworten:

175

Die Art und Weise, wie ich dieses Problem gelöst habe, besteht darin, das contentOffsetentsprechend dem contentInsetin UITableViewControllerDelegate(erweitert UIScrollViewDelegate) wie folgt anzupassen :

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

Das einzige Problem hierbei ist, dass es beim Zurückblättern nach oben etwas an Sprungkraft verliert.


{HINWEIS: Die "40" sollte die genaue Höhe IHRES Abschnitts 0-Headers sein. Wenn Sie eine Zahl verwenden, die größer als die Kopfhöhe Ihres Abschnitts 0 ist, werden Sie feststellen, dass das Fingergefühl beeinträchtigt ist (versuchen Sie es wie "1000" und Sie werden sehen, dass das Sprungverhalten oben etwas seltsam ist). Wenn die Zahl mit der Kopfhöhe Ihres Abschnitts 0 übereinstimmt, scheint das Fingergefühl entweder perfekt oder nahezu perfekt zu sein.}

awulf
quelle
1
Perfekte Lösung als die oben genannte.
Prathumca
4
Danke dir! Dies ist eine perfekte Lösung. Haben Sie die Lösung für die Abschnittsfußzeile?
Tuan Nguyen
12
Diese Lösung behandelt das Tippen auf die Menüleiste nicht richtig, wodurch zum Anfang der Liste gescrollt werden soll.
Reid Ellis
wenn u das gleiche Verhalten für Abschnitt Fußzeile Ansicht muß nur die letzte Zeile wie folgt ändern: scrollView.contentInset = UIEdgeInsetsMake (0, 0, sectionHeaderHeight, 0)
alex
Dies scheint ausreichend zu sein: scrollView.contentInset = UIEdgeInsetsMake (scrollView.contentOffset.y> = 0? -ScrollView.contentOffset.y: 0, 0, 0, 0);
MacMark
85

Sie können auch einen Abschnitt mit null Zeilen oben hinzufügen und einfach die Fußzeile des vorherigen Abschnitts als Überschrift für den nächsten verwenden.

voidStern
quelle
13
In meinem Fall, in dem ich mehr als 2 Abschnitte habe, wird die Fußzeile unten verankert.
Joseph Lin
3
Dies ist kreativ, aber Sie müssen den Indexpfad anpassen, wenn Sie einen NSFetchedResultsController zum Laden der Tabelle verwenden.
XJones
+1 bei weitem die BESTE Lösung - ich brauchte 3 Zeilen, um sie zu implementieren!
Jon
Brilliant Brilliant Brilliant :-)
iphonic
Wie würde dies für eine Fußzeile funktionieren, die verankert? Würde mich über Hilfe freuen! Danke
darwindeeds
36

Wenn ich das tun würde, würde ich die Tatsache ausnutzen, dass UITableViews im Plain-Stil die klebrigen Überschriften haben und solche im Grouped-Stil nicht. Ich würde wahrscheinlich zumindest versuchen, eine benutzerdefinierte Tabellenzelle zu verwenden, um das Erscheinungsbild von einfachen Zellen in einer gruppierten Tabelle nachzuahmen.

Ich habe das noch nicht ausprobiert, daher funktioniert es möglicherweise nicht, aber das würde ich vorschlagen.

Colin Barrett
quelle
Würde wahrscheinlich funktionieren, aber wurde es versucht? Und es scheint eine Menge Arbeit zu sein, wenn die Antwort von @ voidStern perfekt funktioniert !!
Bentford
Die Antwort von voidStern funktioniert bei mir nicht, wenn ich mehr als zwei Abschnitte habe. Colins Antwort ist einfacher / eleganter, ohne dass die Abschnittsnummer manuell verschoben und die Abschnittsanzahl hinzugefügt werden muss.
Joseph Lin
Tipps: Verwenden Sie tableView.separatorColor = [UIColor clearColor];diese Option, um eine einfache Tabellenansicht nachzuahmen.
Joseph Lin
3
Ich habe es versucht, aber wenn ich die gruppierten Tabellenzellen nicht wie die einfachen aussehen lassen konnte, dh den linken und rechten Rand auf beiden Seiten der Zellen entfernen. Wie hast du das gemacht?
Adam Carter
1
Vielen Dank, dass Sie die Dinge über UITableViewStyle klargestellt haben, dh gruppiert und einfach, was entscheidet, ob die Kopf- / Fußzeile des Abschnitts von tableview klebrig ist oder nicht. Vielen Dank @Colin Barrett
Dhaval H. Nena
28

Ich weiß, dass es spät ist, aber ich habe die endgültige Lösung gefunden!

Wenn Sie 10 Abschnitte haben, lassen Sie die dataSource 20 zurückgeben. Verwenden Sie gerade Zahlen für Abschnittsüberschriften und ungerade Zahlen für Abschnittsinhalte. etwas wie das

- (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á! : D.

LocoMike
quelle
großartige Idee. Aber wenn Sie Abschnittsindex-Titel haben, vermute ich, dass dies sie durcheinander bringen wird.
Roocell
Warum? Sie können dasselbe mit Abschnittsüberschriften tun. Denken Sie nur an Null für ungerade Zahlen und an einen Titel für die gerade Zahl.
LocoMike
1
Ja, diese Methode funktioniert hervorragend. Es war viel Buchhaltung (wahrscheinlich damit zu tun, wie ich die Abschnittsüberschriften bekommen muss), aber es hat funktioniert. Der Trick ist, dass numberOfRowsInSection und cellForRowAtIndexPath if verwenden (Abschnitt% 2! = 0 && Abschnitt! = 0), während die Funktionen titleForHeaderInSection und die anderen Abschnittsindex if (Abschnitt% 2 == 0) verwenden
roocell
Der Urheber sollte dies als Antwort wählen. Es wäre großartig, wenn es eine Möglichkeit gäbe, uitableview in eine Unterklasse zu unterteilen, um die Abschnittsüberschriften automatisch zu verankern.
Roocell
Das hat bei mir am besten funktioniert. Ich habe zuerst die Lösung von @ Colin ausprobiert, aber sie hat mit den stark angepassten Lösungen, UITableViewdie ich verwende, nicht gut funktioniert .
Kubi
15

Es gibt mehrere Dinge, die getan werden müssen, um dieses Problem auf nicht hackige Weise zu lösen:

  1. Stellen Sie den Stil der Tabellenansicht auf ein UITableViewStyleGrouped
  2. Stellen Sie die Tabellenansicht backgroundColorauf ein[UIColor clearColor]
  3. Setzen Sie die backgroundViewZelle für jede Tabellenansicht auf eine leere Ansicht mitbackgroundColor [UIColor clearColor]
  4. Stellen Sie bei Bedarf die Tabellenansicht rowHeightentsprechend ein oder überschreiben Sie sie, tableView:heightForRowAtIndexPath:wenn einzelne Zeilen unterschiedliche Höhen haben.
Neil Gall
quelle
(+1) @Neil, ich habe Ihre Antwort versucht, aber leider haben UITableViewStyleGroupeddie Tabellenzellen zusätzliche Ränder, die ihre Ausrichtung mit der Kopfzeile ändern. Dies ist ein Problem, wenn Sie tatsächlich eine mehrspaltige Tabelle darstellen und den Header verwenden möchten, um Spaltentitel anzuzeigen (und dann die einzelnen Tabelleneinträge an diesen Titeln ausrichten möchten).
Brainjam
15

Quoted hier , eine schnelle Lösung des IB verwenden. Das gleiche kann programmatisch gemacht werden, wenn auch ganz einfach.

Ein wahrscheinlich einfacher Weg, dies zu erreichen (mit IB):

Ziehen Sie eine UIView auf Ihre TableView, um sie zu ihrer Header-Ansicht zu machen.

  1. Stellen Sie die Höhe der Header-Ansicht auf 100 Pixel ein
  2. Setzen Sie die Tabellenansicht contentInset (oben) auf -100
  3. Abschnittsüberschriften werden jetzt wie in jeder normalen Zelle gescrollt.

Einige Leute sagten, dass diese Lösung den ersten Header verbirgt, aber ich habe kein solches Problem bemerkt. Es hat perfekt für mich funktioniert und war bei weitem die einfachste Lösung, die ich bisher gesehen habe.

Doc
quelle
Beachten Sie, dass Sie die Ansicht wahrscheinlich so einstellen sollten, dass eine Hintergrundfarbe in Klarfarbe verwendet wird. Andernfalls wird beim Abspringen Weiß angezeigt, wenn Sie über den oberen Rand scrollen.
Doc
3
Es verbirgt meinen ersten Kopfball
Leena
Leena, auf welcher iOS-Version laufen Sie? Ist die Ansicht ein UITableViewController oder eine UIView mit einer UITableView? Ich bin mir nicht sicher, warum diese Lösung für einige Leute den ersten Header verbirgt, also versuche ich, Unstimmigkeiten zu finden.
Doc
Diese Lösung ist perfekt. Ich bin auf der Suche nach einem unendlichen Erscheinungsbild der oberen und unteren Zellen im Hintergrund - dies schafft es voll und ganz. Nett!
Taylor Halliday
Diese Lösung ist ausgezeichnet. Einfacher zu erreichen als die anderen Antworten in diesem Thread. Meiner Meinung nach sollte dies die akzeptierte Antwort sein.
John Rogers
15

Ich war mit den hier beschriebenen Lösungen bisher nicht zufrieden und habe versucht, sie zu kombinieren. Das Ergebnis ist der folgende Code, der von @awulf und @cescofry inspiriert wurde. Es funktioniert bei mir, weil ich keinen echten Header für die Tabellenansicht habe. Wenn Sie bereits eine Kopfzeile für die Tabellenansicht haben, müssen Sie möglicherweise die Höhe anpassen.

// 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
quelle
Dies war die einfachste Lösung, die ich gefunden habe.
Zorayr
Dies funktionierte für mich unter iOS9.2. Obwohl es sich um eine ältere Antwort handelt, ist sie dennoch gültig. Und der erste Abschnittskopf wurde nicht ausgeblendet. Funktioniert und funktioniert perfekt.
idStar
Perfekt. Wenn Ihre Tabellenansicht bereits einen Header hat, erhöhen Sie einfach die Höhe um den Versatz und erhöhen Sie dann die oberste Einschränkungskonstante des Header-Inhalts, um den Inhalt an die ursprüngliche Position zu verschieben
Jason,
14

Ändern Sie einfach den TableView-Stil:

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

UITableViewStyle-Dokumentation :

UITableViewStylePlain- Eine einfache Tabellenansicht. Alle Kopf- oder Fußzeilen von Abschnitten werden als Inline-Trennzeichen angezeigt und schweben, wenn die Tabellenansicht gescrollt wird.

UITableViewStyleGrouped- Eine Tabellenansicht, deren Abschnitte unterschiedliche Gruppen von Zeilen darstellen. Die Kopf- und Fußzeilen des Abschnitts schweben nicht.

Arthur S.
quelle
tolle Antwort, hat für mich gearbeitet. Keine Notwendigkeit, um zu arbeiten
Shams Ahmed
8

Wählen Sie Grouped TableView-Stil

Wählen Sie im Attributinspektor Ihrer tableView im Storyboard den Stil "Gruppierte Tabellenansicht" aus.

Arjun Shukla
quelle
5

Stellen Sie die HeaderView der Tabelle mit einer transparenten Ansicht mit derselben Höhe der Header in der Schnittansicht ein. Starten Sie auch die Tabellenansicht mit einem Frame in der Höhe.

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
quelle
4

Ich habe eine alternative Lösung gefunden. Verwenden Sie die erste Zelle jedes Abschnitts anstelle eines echten Header-Abschnitts. Diese Lösung erscheint nicht so sauber, funktioniert aber so gut. Sie können eine definierte Prototypzelle für Ihren Header-Abschnitt und in der Methode cellForRowAtIndexPath verwenden Fragen Sie nach der indexPath.row == 0, wenn true, verwenden Sie die Prototypzelle des Header-Abschnitts, andernfalls verwenden Sie Ihre Standard-Prototypzelle.

AlexBB
quelle
Wenn Sie weiterhin mit indexPath.row& arbeiten möchten indexPath.section, stellen Sie sicher, dass Sie eine Höhe von 0.0ffor zurückgeben, - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)sectiondamit Ihre Header unsichtbar sind.
Suppe
4

Ändern Sie Ihren TableView-Stil:

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

Gemäß Apple-Dokumentation für UITableView:

UITableViewStylePlain- Eine einfache Tabellenansicht. Alle Kopf- oder Fußzeilen von Abschnitten werden als Inline-Trennzeichen angezeigt und schweben, wenn die Tabellenansicht gescrollt wird.

UITableViewStyleGrouped- Eine Tabellenansicht, deren Abschnitte unterschiedliche Gruppen von Zeilen darstellen. Die Kopf- und Fußzeilen des Abschnitts schweben nicht. Hoffe, diese kleine Änderung wird Ihnen helfen ..

Aks
quelle
2

Nachdem der gruppierte Stil im Grunde genommen genauso aussieht wie der einfache Stil in iOS 7 (in Bezug auf Ebenheit und Hintergrund), bestand für uns die beste und einfachste (dh am wenigsten hackige) Lösung darin, den Stil der Tabellenansicht einfach in gruppiert zu ändern. Das Aufbocken mit contentInsets war immer ein Problem, wenn wir oben eine Scroll-Away-Navigationsleiste integriert haben. Bei einem gruppierten Tabellenansichtsstil sieht es genauso aus (mit unseren Zellen) und die Abschnittsüberschriften bleiben fest. Keine Scrolling-Verrücktheit.

Greg Combs
quelle
Dies ist die beste Lösung, insbesondere wenn die Zellen benutzerdefiniert sind. Es scheint einfach das "Halten" der Abschnittsüberschrift zu stoppen, wenn der Bildlauf oben ankommt.
Recycelter Stahl
1

Weisen Sie Ihrer tableView einen negativen Einschub zu. Wenn Sie 22px hohe Abschnittsüberschriften haben und nicht möchten, dass diese klebrig sind, fügen Sie direkt nach dem erneuten Laden von Daten Folgendes hinzu:

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

Funktioniert wie ein Zauber für mich. Funktioniert auch für Abschnittsfußzeilen. Weisen Sie stattdessen einfach den negativen Einschub unten zu.

Mike A.
quelle
Dies hackt nur den ersten Header ab?
Cannyboy
Hat perfekt für mich funktioniert !! Danke
Daniel
0

Ich füge die Tabelle einer Bildlaufansicht hinzu und das scheint gut zu funktionieren.

Dolbex
quelle
0

Überprüfen Sie meine Antwort hier . Dies ist der einfachste Weg, um die nicht schwebenden Abschnittsüberschriften ohne Hacks zu implementieren.

Sumit Anantwar
quelle
0

Die Antwort von @ LocoMike passte am besten zu meiner tableView, brach jedoch auch bei der Verwendung von Fußzeilen. Dies ist also die korrigierte Lösung bei der Verwendung von Kopf- und Fußzeilen:

- (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
quelle
0

Schnelle Version von @awulf Antwort, die großartig funktioniert!

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
quelle
-2

Ich habe gelernt, dass das Festlegen der tableHeaderView-Eigenschaft dies bewirkt, dh:

 tableView.tableHeaderView = customView;

und das ist es.

Soni
quelle