So schweben Sie die Zusatzansicht in UICollectionView wie Abschnittsüberschriften im einfachen UITableView-Stil

68

Ich kämpfe darum, einen "Floating Section Header" -Effekt zu erzielen UICollectionView. Etwas, das einfach genug war UITableView(Standardverhalten für UITableViewStylePlain), scheint UICollectionViewohne viel harte Arbeit unmöglich zu sein. Vermisse ich das Offensichtliche?

Apple bietet keine Dokumentation dazu an. Es scheint, dass man UICollectionViewLayoutein benutzerdefiniertes Layout unterordnen und implementieren muss, um diesen Effekt zu erzielen. Dies erfordert viel Arbeit bei der Implementierung der folgenden Methoden:

Methoden zum Überschreiben

Jedes Layoutobjekt sollte die folgenden Methoden implementieren:

collectionViewContentSize
layoutAttributesForElementsInRect:
layoutAttributesForItemAtIndexPath:
layoutAttributesForSupplementaryViewOfKind:atIndexPath: (if your layout supports supplementary views)
layoutAttributesForDecorationViewOfKind:atIndexPath: (if your layout supports decoration views)
shouldInvalidateLayoutForBoundsChange:

Mir ist jedoch nicht klar, wie ich die Zusatzansicht über die Zellen schweben lassen und am oberen Rand der Ansicht "bleiben" kann, bis der nächste Abschnitt erreicht ist. Gibt es dafür ein Flag in den Layoutattributen?

Ich hätte verwendet, UITableViewaber ich muss eine ziemlich komplexe Hierarchie von Sammlungen erstellen, die mit einer Sammlungsansicht leicht erreicht werden kann.

Jede Anleitung oder Beispielcode wäre sehr dankbar!

100 Gramm
quelle

Antworten:

69

In iOS9 war Apple so freundlich, eine einfache Eigenschaft in UICollectionViewFlowLayoutaufgerufen hinzuzufügen sectionHeadersPinToVisibleBounds.

Auf diese Weise können Sie die Header in Tabellenansichten so schweben lassen.

let layout = UICollectionViewFlowLayout()
layout.sectionHeadersPinToVisibleBounds = true
layout.minimumInteritemSpacing = 1
layout.minimumLineSpacing = 1
super.init(collectionViewLayout: layout)
ipraba
quelle
Wo füge ich dieses Snippet hinzu
Happiehappie
In Ihrer UICollectionViewController-Init-Methode
ipraba
Was ist, wenn ich einen UIViewController mit einer collectionView darin verwende
Happiehappie
2
Gute Antwort! Ich vermute, dass die obigen Antworten nur eine Lösung für vor iOS 9 sind.
Josip B.
7
Nur eine kleine Korrektur: yourCollectionView.collectionViewLayoutUICollectionViewFlowLayout(self.yourCollectionView.collectionViewLayout as! UICollectionViewFlowLayout).sectionHeadersPinToVisibleBounds = true
Um sie
47

Implementieren Sie entweder die folgenden Delegatenmethoden:

collectionView:layout:sizeForItemAtIndexPath:
– collectionView:layout:insetForSectionAtIndex:
– collectionView:layout:minimumLineSpacingForSectionAtIndex:
– collectionView:layout:minimumInteritemSpacingForSectionAtIndex:
– collectionView:layout:referenceSizeForHeaderInSection:
– collectionView:layout:referenceSizeForFooterInSection:

In Ihrem View Controller, der Ihre :cellForItemAtIndexPathMethode hat (geben Sie einfach die richtigen Werte zurück). Anstatt die Delegatmethoden zu verwenden, können Sie diese Werte auch direkt in Ihrem Layoutobjekt festlegen, z [layout setItemSize:size];.

Mit einer dieser Methoden können Sie Ihre Einstellungen in Code und nicht in IB festlegen, da diese beim Festlegen eines benutzerdefinierten Layouts entfernt werden. Denken Sie daran, auch <UICollectionViewDelegateFlowLayout>zu Ihrer .h-Datei hinzuzufügen !

Erstellen Sie eine neue Unterklasse von UICollectionViewFlowLayout, nennen Sie sie wie gewünscht und stellen Sie sicher, dass die H-Datei Folgendes enthält:

#import <UIKit/UIKit.h>

@interface YourSubclassNameHere : UICollectionViewFlowLayout

@end

Stellen Sie in der Implementierungsdatei Folgendes sicher:

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {

    NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy];
    UICollectionView * const cv = self.collectionView;
    CGPoint const contentOffset = cv.contentOffset;

    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];
    for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
        if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) {
            [missingSections addIndex:layoutAttributes.indexPath.section];
        }
    }
    for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {
        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
            [missingSections removeIndex:layoutAttributes.indexPath.section];
        }
    }

    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {

        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];

        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];

        [answer addObject:layoutAttributes];

    }];

    for (UICollectionViewLayoutAttributes *layoutAttributes in answer) {

        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {

            NSInteger section = layoutAttributes.indexPath.section;
            NSInteger numberOfItemsInSection = [cv numberOfItemsInSection:section];

            NSIndexPath *firstCellIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
            NSIndexPath *lastCellIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section];

            NSIndexPath *firstObjectIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
            NSIndexPath *lastObjectIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section];

            UICollectionViewLayoutAttributes *firstObjectAttrs;
            UICollectionViewLayoutAttributes *lastObjectAttrs;

            if (numberOfItemsInSection > 0) {
                firstObjectAttrs = [self layoutAttributesForItemAtIndexPath:firstObjectIndexPath];
                lastObjectAttrs = [self layoutAttributesForItemAtIndexPath:lastObjectIndexPath];
            } else {
                firstObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                                    atIndexPath:firstObjectIndexPath];
                lastObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter
                                                                   atIndexPath:lastObjectIndexPath];
            }

            CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.y = MIN(
                           MAX(
                               contentOffset.y + cv.contentInset.top,
                               (CGRectGetMinY(firstObjectAttrs.frame) - headerHeight)
                               ),
                           (CGRectGetMaxY(lastObjectAttrs.frame) - headerHeight)
                           );

            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect){
                .origin = origin,
                .size = layoutAttributes.frame.size
            };

        }

    }

    return answer;

}

- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBound {

    return YES;

}

Wählen Sie im Interface Builder "Benutzerdefiniert" für das Ablauflayout und anschließend die soeben erstellte Klasse "YourSubclassNameHere". Und Renn!

(Hinweis: Der obige Code berücksichtigt möglicherweise nicht die Werte von contentInset.bottom oder insbesondere große oder kleine Fußzeilenobjekte oder Sammlungen mit 0 Objekten, aber ohne Fußzeile.)

topLayoutGuide
quelle
3
Wenn numberOfItemsInSection == 0, erhalten Sie einen EXC_ARITHMETIC code=EXC_I386_DIV(durch Null dividieren?) Absturz in dieser Zeile : UICollectionViewLayoutAttributes *firstCellAttrs = [self layoutAttributesForItemAtIndexPath:firstCellIndexPath];. Ich habe auch festgestellt, dass die contentOffsetTeile dieses Codes den obersten Wert der Sammlungsansicht in meiner Implementierung nicht berücksichtigen (möglicherweise im Zusammenhang mit der vorherigen Ausgabe). Schlägt eine Codeänderung / gist / etc. Vor.
toblerpwn
3
gist.github.com/toblerpwn/5393460 - Sie können jederzeit iterieren, insbesondere in Bezug auf die im Inhalt angegebenen Einschränkungen. :)
toblerpwn
Große Hilfe, danke. Dies funktionierte perfekt mit den PSTCollectionView-Kompatibilitätsklassen, indem die relevanten Klassen (UICollectionView / PSTCollectionView, ... usw.) umbenannt wurden. Github.com/steipete/PSTCollectionView
Chris Blunt
1
Sollte dies nicht möglich sein, ohne das Layout bei jeder Bouns-Änderung ungültig zu machen?
Mattsson
1
@cocotutch Haben Sie seit dem Start des iOS 8 SDK Probleme mit der Verwendung dieser Funktion festgestellt? Meine Zellenlayouts in diesem Flow haben standardmäßig eine Größe von 50 x 50, obwohl ich sie definiert habe collectionView:layout:sizeForItemAtIndexPath:. Insbesondere beträgt der Inhalt der inneren Zelle 50 x 50, aber die Größe der Zelle ist immer noch korrekt. Tritt nur beim Erstellen mit iOS 8 SDK auf, läuft jedoch unter iOS 7.0.X. Das Erstellen gegen iOS 7.1 SDK und das Ausführen unter 7.0.X funktioniert einwandfrei.
Matt Baker
8

Wenn Sie eine einzelne Header-Ansicht haben, die oben in Ihrer UICollectionView angeheftet werden soll, ist dies eine relativ einfache Möglichkeit. Beachten Sie, dass dies so einfach wie möglich sein soll - es wird davon ausgegangen, dass Sie einen einzelnen Header in einem einzelnen Abschnitt verwenden.

//Override UICollectionViewFlowLayout class
@interface FixedHeaderLayout : UICollectionViewFlowLayout
@end

@implementation FixedHeaderLayout
//Override shouldInvalidateLayoutForBoundsChange to require a layout update when we scroll 
- (BOOL) shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
    return YES;
}

//Override layoutAttributesForElementsInRect to provide layout attributes with a fixed origin for the header
- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect {

    NSMutableArray *result = [[super layoutAttributesForElementsInRect:rect] mutableCopy];

    //see if there's already a header attributes object in the results; if so, remove it
    NSArray *attrKinds = [result valueForKeyPath:@"representedElementKind"];
    NSUInteger headerIndex = [attrKinds indexOfObject:UICollectionElementKindSectionHeader];
    if (headerIndex != NSNotFound) {
        [result removeObjectAtIndex:headerIndex];
    }

    CGPoint const contentOffset = self.collectionView.contentOffset;
    CGSize headerSize = self.headerReferenceSize;

    //create new layout attributes for header
    UICollectionViewLayoutAttributes *newHeaderAttributes = [UICollectionViewLayoutAttributes layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader withIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
    CGRect frame = CGRectMake(0, contentOffset.y, headerSize.width, headerSize.height);  //offset y by the amount scrolled
    newHeaderAttributes.frame = frame;
    newHeaderAttributes.zIndex = 1024;

    [result addObject:newHeaderAttributes];

    return result;
}
@end

Siehe: https://gist.github.com/4613982

MikeV
quelle
7

Hier ist meine Einstellung dazu, ich denke, es ist viel einfacher als das, was man oben gesehen hat. Die Hauptquelle der Einfachheit ist, dass ich das Flow-Layout nicht unterklassifiziere, sondern mein eigenes Layout rolle (viel einfacher, wenn Sie mich fragen).

Bitte beachten Sie, dass ich davon ausgehe, dass Sie bereits in der Lage sind, Ihre eigenen benutzerdefinierten UICollectionViewLayoutElemente zu implementieren, die Zellen und Header anzeigen, ohne dass Floating implementiert ist. Sobald Sie diese Implementierung geschrieben haben, ist der folgende Code nur dann sinnvoll. Dies liegt wiederum daran, dass das OP speziell nach dem schwebenden Header-Teil gefragt hat.

ein paar Boni:

  1. Ich schwebe zwei Header, nicht nur einen
  2. Überschriften schieben vorherige Überschriften aus dem Weg
  3. Schau, schnell!

Hinweis:

  1. supplementaryLayoutAttributes enthält alle Header-Attribute ohne Floating implementiert
  2. Ich verwende diesen Code in prepareLayout, da ich alle Berechnungen im Voraus durchführe.
  3. Vergiss nicht, shouldInvalidateLayoutForBoundsChangeauf wahr zu setzen !

// float them headers
let yOffset = self.collectionView!.bounds.minY
let headersRect = CGRect(x: 0, y: yOffset, width: width, height: headersHeight)

var floatingAttributes = supplementaryLayoutAttributes.filter {
    $0.frame.minY < headersRect.maxY
}

// This is three, because I am floating 2 headers
// so 2 + 1 extra that will be pushed away
var index = 3
var floatingPoint = yOffset + dateHeaderHeight

while index-- > 0 && !floatingAttributes.isEmpty {

    let attribute = floatingAttributes.removeLast()
    attribute.frame.origin.y = max(floatingPoint, attribute.frame.origin.y)

    floatingPoint = attribute.frame.minY - dateHeaderHeight
}
Mazyod
quelle
Nicht sicher, was dies bedeutet, der Code ist unvollständig und die Notizen füllen nicht alle Lücken.
SafeFastExpressive
@RandyHill Dieser Code ist keine generische Lösung, sondern eine Anleitung, wie ich schwebende Header erhalten habe. Wenn Sie Probleme haben, einen Teil der Implementierung zu verstehen, fragen Sie einfach. (Ich werde eine zusätzliche Notiz hinzufügen, die meiner Meinung nach die Quelle Ihrer Verwirrung ist).
Mazyod
1
Egal, das ist in Bezug auf die Frage klar. Ich habe meine Abwahl entfernt.
SafeFastExpressive
Haben Sie vielleicht ein Beispielprojekt? Ich versuche 2 schwebende Header zu implementieren und kann es nicht zum Laufen
bringen
4

Wenn Sie bereits das Flow-Layout in Storyboardoder die XibDatei festgelegt haben, versuchen Sie Folgendes:

(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionHeadersPinToVisibleBounds = true
Mohammad Zaid Pathan
quelle
4

Falls jemand in Objective-C nach einer Lösung sucht, fügen Sie diese in viewDidload ein:

    UICollectionViewFlowLayout *flowLayout = 
    (UICollectionViewFlowLayout*)_yourcollectionView.collectionViewLayout;
    [flowLayout setSectionHeadersPinToVisibleBounds:YES];
GeneCode
quelle
3

@iPrabu hatte eine ausgezeichnete Antwort mit sectionHeadersPinToVisibleBounds. Ich möchte nur hinzufügen, dass Sie diese Eigenschaft auch im Interface Builder festlegen können:

  1. Wählen Sie im Dokumentnavigator das Ablauflayoutobjekt aus. (Wenn es reduziert ist, erweitern Sie es zuerst mit der Symbolleistenschaltfläche in der unteren linken Ecke des Editors.)

Auswahl des Flow-Layout-Objekts im Dokumentennavigator.

  1. Öffnen Sie den Identitätsinspektor und fügen Sie ein benutzerdefiniertes Laufzeitattribut mit Schlüsselpfad sectionHeadersPinToVisibleBounds, Typ Boolean und aktiviertem Kontrollkästchen hinzu.

Festlegen des Laufzeitattributs im Identitätsinspektor.

Die Standard-Header-Ansicht hat einen transparenten Hintergrund. Möglicherweise möchten Sie es (teilweise) undurchsichtig machen oder eine Unschärfeeffektansicht hinzufügen.

Constantino Tsarouhas
quelle
2

Ich bin auf dasselbe Problem gestoßen und habe es in meinen Google-Ergebnissen gefunden. Zunächst möchte ich Cocotutch für das Teilen seiner Lösung danken. Ich wollte jedoch, dass meine UICollectionView horizontal scrollt und die Überschriften links vom Bildschirm angezeigt werden, sodass ich die Lösung etwas ändern musste.

Grundsätzlich habe ich das geändert:

        CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
        CGPoint origin = layoutAttributes.frame.origin;
        origin.y = MIN(
                       MAX(
                           contentOffset.y,
                           (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)
                           ),
                       (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
                       );

        layoutAttributes.zIndex = 1024;
        layoutAttributes.frame = (CGRect){
            .origin = origin,
            .size = layoutAttributes.frame.size
        };

dazu:

        if (self.scrollDirection == UICollectionViewScrollDirectionVertical) {
            CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.y = MIN(
                           MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)),
                           (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
                           );

            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect){
                .origin = origin,
                .size = layoutAttributes.frame.size
            };
        } else {
            CGFloat headerWidth = CGRectGetWidth(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.x = MIN(
                           MAX(contentOffset.x, (CGRectGetMinX(firstCellAttrs.frame) - headerWidth)),
                           (CGRectGetMaxX(lastCellAttrs.frame) - headerWidth)
                           );

            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect){
                .origin = origin,
                .size = layoutAttributes.frame.size
            };
        }

Siehe: https://gist.github.com/vigorouscoding/5155703 oder http://www.vigorouscoding.com/2013/03/uicollectionview-with-sticky-headers/

kräftige Kodierung
quelle
2

Ich habe dies mit dem Code von vigorouscoding ausgeführt . Dieser Code berücksichtigte jedoch nicht sectionInset.

Also habe ich diesen Code für vertikales Scrollen geändert

origin.y = MIN(
              MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)),
              (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight)
           );

zu

origin.y = MIN(
           MAX(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight - self.sectionInset.top)),
           (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight + self.sectionInset.bottom)
           );

Wenn Sie Code für horizontales Scrollen möchten, lesen Sie den obigen Code.


quelle
Vielen Dank für das Hinzufügen von Horizontal! :-) -coco
topLayoutGuide
1

Ich habe ein Beispiel für Github hinzugefügt , das ziemlich einfach ist, denke ich.

Grundsätzlich besteht die Strategie darin, ein benutzerdefiniertes Layout bereitzustellen, das bei Änderungen der Grenzen ungültig wird, und Layoutattribute für die Zusatzansicht bereitzustellen, die die aktuellen Grenzen umfassen. Wie andere vorgeschlagen haben. Ich hoffe der Code ist nützlich.

Derrick Hathaway
quelle
Die Kopf- und Fußzeilenansichten in diesem Code verhalten sich anders als die Kopf- und Fußzeilen der Tabellenansicht. Sie bleiben immer haften, auch wenn sie weiter als bis zum Ende gescrollt sind (so dass sie abprallen).
Ortwin Gentz
1

Es gibt einen Fehler in Cocotouchs Beitrag. Wenn der Abschnitt keine Elemente enthält und die Fußzeile des Abschnitts nicht angezeigt wurde, wird die Abschnittsüberschrift außerhalb der Sammlungsansicht angezeigt und der Benutzer kann sie nicht sehen.

In der Tat ändern:

if (numberOfItemsInSection > 0) {
    firstObjectAttrs = [self layoutAttributesForItemAtIndexPath:firstObjectIndexPath];
    lastObjectAttrs = [self layoutAttributesForItemAtIndexPath:lastObjectIndexPath];
} else {
    firstObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                            atIndexPath:firstObjectIndexPath];
    lastObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter
                                                           atIndexPath:lastObjectIndexPath];
}

in:

if (numberOfItemsInSection > 0) {
    firstObjectAttrs = [self layoutAttributesForItemAtIndexPath:firstObjectIndexPath];
    lastObjectAttrs = [self layoutAttributesForItemAtIndexPath:lastObjectIndexPath];
} else {
    firstObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader
                                                            atIndexPath:firstObjectIndexPath];
    lastObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter
                                                           atIndexPath:lastObjectIndexPath];
    if (lastObjectAttrs == nil) {
        lastObjectAttrs = firstObjectAttrs;
    }
}

wird dieses Problem lösen.

WeZZard
quelle
0

VCollectionViewGridLayout erstellt klebrige Header. Es ist ein einfaches Rasterlayout mit vertikalem Bildlauf, das auf TLIndexPathTools basiert . Versuchen Sie, das Beispielprojekt Sticky Headers auszuführen .

Dieses Layout hat auch ein viel besseres Batch-Update-Animationsverhalten als UICollectionViewFlowLayout. Es gibt einige Beispielprojekte, mit denen Sie zwischen den beiden Layouts wechseln können, um die Verbesserung zu demonstrieren.

Timothy Moose
quelle
Das habe ich versucht. Wenn Sie bereits über eine UICollectionView mit einem funktionierenden Datendelegierten verfügen, ist es schwierig, dorthin zu wechseln, da Ihr Datenmodell als TLIndexDataModel modelliert werden muss. Ich habe das aufgegeben.
Xaphod
@xaphod Das tut es eigentlich nicht. In der GitHub-Readme-Datei: "Erfordert TLIndexPathTools für die interne Implementierung. Die Sammlungsansicht selbst muss nicht unbedingt TLIndexPathTools verwenden, die Beispielprojekte jedoch."
Timothy Moose
Ja, das habe ich auch gelesen. In der Praxis ist es nicht richtig. Versuch es.
Xaphod
@xaphod Ich sollte erwähnen, dass ich die Bibliothek geschrieben habe. Ich werde ein Beispielprojekt hinzufügen, das TLIPT nicht verwendet. Die einzige Voraussetzung für die Verwendung dieser Bibliothek ist, dass Sie VCollectionViewGridLayoutDelegatedie Delegatmethoden implementieren müssen , für die selbst kein TLIPT erforderlich ist. Die Hauptabsicht dieser Bibliothek bestand jedoch darin, einige Animationsprobleme mit dem Ablauflayout zu umgehen. Die Funktion für klebrige Überschriften ist zweitrangig, daher gibt es möglicherweise bessere Optionen für diejenigen, die nur an klebrigen Überschriften interessiert sind.
Timothy Moose
Ah ok - nun, ich habe mich sehr bemüht, TLIPT überhaupt nicht zu verwenden, aber ich konnte sehen, dass in der Layoutklasse TLIPT verwendet wurde. Ich konnte es nicht sehen. Sie haben Recht, dass alles, was ich suche, klebrige Header sind ... aber ich hatte noch keinen Erfolg (die obige Lösung von cocotutch funktioniert auch bei mir nicht, was darauf hinweist, dass das Problem auf meiner Seite
fehlerhaft ist
0

Swift 5.0

Fügen Sie Folgendes in Ihre viewDidLoad ein:

if let layout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
    layout.sectionHeadersPinToVisibleBounds = true
}
TimBigDev
quelle
(collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.sectionHeadersPinToVisibleBounds = true
PhoneyDeveloper