UICollectionView flowLayout umschließt Zellen nicht korrekt(iOS)



pinterest collection view (8)

Ich habe eine UICollectionView mit einem FLowLayout. Es wird funktionieren, wie ich die meiste Zeit erwarte, aber hin und wieder wickelt sich eine der Zellen nicht richtig ein. Zum Beispiel die Zelle, die in der ersten "Spalte" der dritten Zeile enthalten sein sollte, wenn sie tatsächlich in der zweiten Zeile folgt, und es gibt nur eine leere Stelle, wo sie sein sollte (siehe Diagramm unten). Alles, was du von dieser Rouge-Zelle sehen kannst, ist die linke Seite (der Rest ist abgeschnitten) und der Platz, an dem es sein sollte, ist leer.

Dies geschieht nicht konsequent; es ist nicht immer dieselbe Reihe. Sobald es passiert ist, kann ich nach oben und dann zurück scrollen und die Zelle wird sich selbst repariert haben. Oder, wenn ich die Zelle drücke (die mich durch einen Druck zur nächsten Ansicht bringt) und dann zurückspringe, sehe ich die Zelle in der falschen Position und dann springt sie zur richtigen Position.

Die Scroll-Geschwindigkeit scheint es einfacher zu machen, das Problem zu reproduzieren. Wenn ich langsam scrolle, kann ich die Zelle immer noch in der falschen Position sehen, aber dann springt sie sofort in die richtige Position.

Das Problem begann, als ich die Abschnittseinfügungen hinzufügte. Zuvor hatte ich die Zellen fast bündig gegen die Sammlungsgrenzen (wenig oder keine Einsätze) und ich habe das Problem nicht bemerkt. Aber das bedeutete, dass die rechte und linke Seite der Sammlungsansicht leer war. Dh, konnte nicht scrollen. Außerdem war die Bildlaufleiste nicht rechtsbündig.

Ich kann das Problem sowohl auf Simulator als auch auf einem iPad 3 lösen.

Ich schätze, dass das Problem wegen der linken und rechten Abschnittseinsätze passiert ... Aber wenn der Wert falsch ist, würde ich erwarten, dass das Verhalten konsistent ist. Ich frage mich, ob das ein Fehler mit Apple sein könnte? Oder vielleicht liegt das an einem Aufbau der Einsätze oder etwas Ähnliches ...

Irgendwelche Lösungen / Workarounds werden geschätzt.

Follow-up : Ich habe diese Antwort unten von Nick seit über 6 Monaten, 12 Monaten und 2 Jahren ohne Probleme benutzt (falls Leute sich fragen, ob es Löcher in dieser Antwort gibt - ich habe noch keine gefunden). Gut gemacht, Nick.

https://ffff65535.com


Die obigen Antworten funktionieren nicht für mich, aber nach dem Herunterladen der Bilder habe ich ersetzt

[self.yourCollectionView reloadData]

mit

[self.yourCollectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];

um zu aktualisieren und es können alle Zellen korrekt angezeigt werden, können Sie es versuchen.


Dies kann etwas spät sein, stellen Sie aber sicher, dass Sie Ihre Attribute in prepare() wenn möglich.

Mein Problem war, dass die Zellen angelegt wurden und dann in layoutAttributesForElements aktualisiert layoutAttributesForElements . Dies führte zu einem Flickereffekt, als neue Zellen in Sicht kamen.

Indem Sie die gesamte Attributlogik in prepare UICollectionViewCell.apply() Sie sie in UICollectionViewCell.apply() , um das Flimmern zu beseitigen und eine glatte Butterzelle mit 😊 zu erzeugen


Es gibt einen Fehler in der Implementierung von layoutAttributesForElementsInRect durch UICollectionViewFlowLayout, die dazu führt, dass in bestimmten Fällen, in denen Abschnittseinfügungen enthalten sind, ZWEI Attributobjekte für eine einzelne Zelle zurückgegeben werden. Eines der zurückgegebenen Attributobjekte ist ungültig (außerhalb der Grenzen der Sammlungsansicht) und das andere ist gültig. Im Folgenden finden Sie eine Unterklasse von UICollectionViewFlowLayout, die das Problem dadurch behebt, dass Zellen außerhalb der Grenzen der Sammlungsansicht ausgeschlossen werden.

// NDCollectionViewFlowLayout.h
@interface NDCollectionViewFlowLayout : UICollectionViewFlowLayout
@end

// NDCollectionViewFlowLayout.m
#import "NDCollectionViewFlowLayout.h"
@implementation NDCollectionViewFlowLayout
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
  NSArray *attributes = [super layoutAttributesForElementsInRect:rect];
  NSMutableArray *newAttributes = [NSMutableArray arrayWithCapacity:attributes.count];
  for (UICollectionViewLayoutAttributes *attribute in attributes) {
    if ((attribute.frame.origin.x + attribute.frame.size.width <= self.collectionViewContentSize.width) &&
        (attribute.frame.origin.y + attribute.frame.size.height <= self.collectionViewContentSize.height)) {
      [newAttributes addObject:attribute];
    }
  }
  return newAttributes;
}
@end

Sieh this .

Andere Antworten schlagen vor, YES von shouldInvalidateLayoutForBoundsChange zurückzugeben, aber dies verursacht unnötige Neuberechnung und löst das Problem nicht einmal vollständig.

Meine Lösung löst den Fehler vollständig und sollte keine Probleme verursachen, wenn Apple die Ursache beseitigt.


Fügen Sie dies in den ViewController ein, der die Sammlungsansicht besitzt

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

Ich habe Apple einen Fehlerbericht hinzugefügt. Was für mich funktioniert, ist, den unteren Abschnitt auf einen Wert unterhalb des oberen Einschubs zu setzen.


Ich habe das gleiche Problem mit dem Entfernen von Zellen auf dem iPhone mit Hilfe eines UICollectionViewFlowLayout und war daher froh, einen Beitrag zu finden. Ich weiß, dass Sie das Problem auf einem iPad haben, aber ich UICollectionView dies, weil ich denke, dass es ein generelles Problem mit der UICollectionView . Also hier ist was ich herausgefunden habe.

Ich kann bestätigen, dass das sectionInset für dieses Problem relevant ist. Außerdem hat die headerReferenceSize Einfluss darauf, ob eine Zelle versetzt wird oder nicht. (Dies ist sinnvoll, da es zur Berechnung des Ursprungs benötigt wird.)

Leider müssen sogar unterschiedliche Bildschirmgrößen berücksichtigt werden. Beim Spielen mit den Werten für diese beiden Eigenschaften habe ich festgestellt, dass eine bestimmte Konfiguration entweder auf (3,5 "und 4"), auf keiner oder nur auf einer der Bildschirmgrößen funktioniert hat. Normalerweise keiner von ihnen. (Dies macht auch Sinn, da sich die Grenzen der UICollectionView ändern, daher habe ich keine Disparität zwischen Retina und Nicht-Retina UICollectionView .)

Ich habe die sectionInset und headerReferenceSize abhängig von der Bildschirmgröße festgelegt. Ich habe etwa 50 Kombinationen ausprobiert, bis ich Werte gefunden habe, unter denen das Problem nicht mehr auftrat und das Layout visuell akzeptabel war. Es ist sehr schwierig, Werte zu finden, die auf beiden Bildschirmgrößen funktionieren.

Zusammenfassend kann ich Ihnen nur empfehlen, mit den Werten herumzuspielen, diese auf verschiedenen Bildschirmgrößen zu überprüfen und zu hoffen, dass Apple dieses Problem beheben wird.


Ich habe gerade ein ähnliches Problem mit Zellen gefunden, die verschwinden, nachdem UICollectionView auf iOS 10 scrollt (hat keine Probleme auf iOS 6-9).

Subclassing von UICollectionViewFlowLayout und überschreiben Methode LayoutAttributesForElementsInRect: funktioniert in meinem Fall nicht.

Die Lösung war einfach genug. Momentan benutze ich eine Instanz von UICollectionViewFlowLayout und setze sowohl itemSize als auch estimatedItemSize (ich habe shortedItemSize vorher noch nicht benutzt) und setze es auf eine Größe ungleich Null. Die tatsächliche Größe wird in der Auflistung berechnet: layout: sizeForItemAtIndexPath: method.

Außerdem habe ich einen Aufruf der invalidateLayout-Methode von layoutSubviews entfernt, um unnötiges Neuladen zu vermeiden.


Ich hatte dieses Problem auch für ein grundlegendes Gridview-Layout mit Einfügungen für Ränder. Das begrenzte Debugging, das ich für jetzt durchgeführt habe, implementiert - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect in meiner UICollectionViewFlowLayout-Unterklasse und protokolliert, was die Superklassenimplementierung zurückgibt, was das Problem deutlich zeigt.

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSArray *attrsList = [super layoutAttributesForElementsInRect:rect];

    for (UICollectionViewLayoutAttributes *attrs in attrsList) {
        NSLog(@"%f %f", attrs.frame.origin.x, attrs.frame.origin.y);
    }

    return attrsList;
}

Durch die Implementierung von - (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath kann ich auch sehen, dass es die falschen Werte für itemIndexPath.item == 30 zurückgibt, was Faktor 10 der Anzahl meiner Zellen pro Zeile ist, nicht sicher, ob das ist relevant.

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath {
    UICollectionViewLayoutAttributes *attrs = [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath];

    NSLog(@"initialAttrs: %f %f atIndexPath: %d", attrs.frame.origin.x, attrs.frame.origin.y, itemIndexPath.item);

    return attrs;
}

Da die Zeit für mehr Debugging zu kurz ist, wurde die Sammelzugriffsbreite mit der Problemumgehung, die ich jetzt gemacht habe, um einen Betrag verringert, der dem linken und rechten Rand entspricht. Ich habe einen Header, der immer noch die volle Breite benötigt, also habe ich clipsToBounds = NO in meiner Collectionview gesetzt und dann auch die linken und rechten Einfügungen entfernt, scheint zu funktionieren. Damit die Header-Ansicht dann beibehalten wird, müssen Sie Frame-Verschiebung und Dimensionierung in den Layout-Methoden implementieren, die mit der Rückgabe von layoutAttributes für die Header-Ansicht beauftragt werden.





uicollectionviewcell