Ich habe ein UICollectionView
mit einem FLowLayout. Es wird die meiste Zeit so funktionieren, wie ich es erwartet habe, aber hin und wieder wird eine der Zellen nicht richtig gewickelt. Zum Beispiel die Zelle, die sich in der ersten "Spalte" der dritten Zeile befinden sollte, wenn sie tatsächlich in der zweiten Zeile nachläuft und nur ein leerer Bereich vorhanden ist, in dem sie sich befinden sollte (siehe Abbildung unten). Alles, was Sie von dieser Rougezelle sehen können, ist die linke Seite (der Rest ist abgeschnitten) und die Stelle, an der sie sein sollte, ist leer.
Dies geschieht nicht konsequent; Es ist nicht immer dieselbe Zeile. Sobald es passiert ist, kann ich nach oben und dann zurück scrollen und die Zelle hat sich selbst repariert. Wenn ich auf die Zelle drücke (die mich per Push zur nächsten Ansicht bringt) und dann zurückspringe, sehe ich die Zelle an der falschen Position und springe dann zur richtigen Position.
Die Bildlaufgeschwindigkeit scheint es einfacher zu machen, das Problem zu reproduzieren. Wenn ich langsam scrolle, sehe ich immer noch hin und wieder die Zelle an der falschen Position, aber dann springt sie sofort an die richtige Position.
Das Problem begann, als ich die Abschnitte einfügte. Zuvor hatte ich die Zellen fast bündig mit den Sammlungsgrenzen (wenig oder keine Einfügungen) und ich bemerkte das Problem nicht. Dies bedeutete jedoch, dass rechts und links von der Sammlungsansicht leer war. Dh konnte nicht scrollen. Außerdem war die Bildlaufleiste nicht bündig nach rechts.
Ich kann das Problem sowohl auf dem Simulator als auch auf einem iPad 3 lösen.
Ich denke, das Problem tritt aufgrund der Einfügungen im linken und rechten Abschnitt auf ... Aber wenn der Wert falsch ist, würde ich erwarten, dass das Verhalten konsistent ist. Ich frage mich, ob dies ein Fehler bei Apple sein könnte. Oder vielleicht liegt dies an einem Aufbau der Einsätze oder Ähnlichem.
Follow-up : Ich verwende diese Antwort von Nick seit über 2 Jahren ohne Probleme (falls sich die Leute fragen, ob diese Antwort Lücken enthält - ich habe noch keine gefunden). Gut gemacht, Nick.
quelle
Fügen Sie dies in den viewController ein, dem die Sammlungsansicht gehört
- (void)viewWillLayoutSubviews { [super viewWillLayoutSubviews]; [self.collectionView.collectionViewLayout invalidateLayout]; }
quelle
invalidateLayout
nur einmal.Ich habe ähnliche Probleme in meiner iPhone-Anwendung entdeckt. Die Suche im Apple Dev Forum brachte mir diese geeignete Lösung, die in meinem Fall funktioniert hat und wahrscheinlich auch in Ihrem Fall:
Unterklasse
UICollectionViewFlowLayout
und Überschreibung,shouldInvalidateLayoutForBoundsChange
um zurückzukehrenYES
.//.h @interface MainLayout : UICollectionViewFlowLayout @end
und
//.m #import "MainLayout.h" @implementation MainLayout -(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{ return YES; } @end
quelle
Eine schnelle Version von Nick Snyders Antwort:
class NDCollectionViewFlowLayout : UICollectionViewFlowLayout { override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { let attributes = super.layoutAttributesForElements(in: rect) let contentSize = collectionViewContentSize return attributes?.filter { $0.frame.maxX <= contentSize.width && $0.frame.maxY < contentSize.height } } }
quelle
Ich hatte dieses Problem auch bei einem grundlegenden Rasteransichtslayout mit Einfügungen für Ränder. Das begrenzte Debugging, das ich jetzt durchgeführt habe, ist die Implementierung
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
in meiner UICollectionViewFlowLayout-Unterklasse und die Protokollierung der Rückgabe der Superklassenimplementierung, 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
- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath
kann ich auch feststellen, dass die falschen Werte für itemIndexPath.item == 30 zurückgegeben werden. Dies ist der Faktor 10 der Anzahl der Zellen pro Zeile in meiner Rasteransicht. Ich bin mir nicht sicher, ob dies relevant ist.- (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 ich nicht genug Zeit für mehr Debugging habe, hat die Problemumgehung, die ich jetzt durchgeführt habe, die Breite meiner Sammlungsansichten um einen Betrag reduziert, 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 Sammlungsansicht gesetzt und dann auch die linken und rechten Einfügungen entfernt, scheint zu funktionieren. Damit die Kopfzeilenansicht dann an Ort und Stelle bleibt, müssen Sie die Rahmenverschiebung und -größe in den Layoutmethoden implementieren, die mit der Rückgabe von layoutAttributes für die Kopfzeilenansicht beauftragt sind.
quelle
Ich habe Apple einen Fehlerbericht hinzugefügt. Was für mich funktioniert, ist, den unteren AbschnittInset auf einen Wert zu setzen, der kleiner als der obere Einschub ist.
quelle
Ich hatte das gleiche Problem mit dem Entladen von Zellen auf dem iPhone mit einem
UICollectionViewFlowLayout
und war daher froh, Ihren Beitrag zu finden. Ich weiß, dass Sie das Problem auf einem iPad haben, aber ich poste dies, weil ich denke, dass es ein allgemeines Problem mit dem istUICollectionView
. Also hier ist, was ich herausgefunden habe.Ich kann bestätigen, dass das
sectionInset
für dieses Problem relevant ist. Daneben hat dasheaderReferenceSize
auch Einfluss darauf, ob eine Zelle verdrängt wird oder nicht. (Dies ist sinnvoll, da es zur Berechnung des Ursprungs benötigt wird.)Leider müssen auch unterschiedliche Bildschirmgrößen berücksichtigt werden. Beim Herumspielen mit den Werten für diese beiden Eigenschaften stellte ich fest, dass eine bestimmte Konfiguration entweder auf beiden (3,5 "und 4"), auf keiner oder nur auf einer der Bildschirmgrößen funktioniert. Normalerweise keiner von ihnen. (Dies ist auch sinnvoll, da die Grenzen der
UICollectionView
ich aufgrund Veränderungen keine Unterschiede zwischen Netzhaut und Nicht-Netzhaut festgestellt habe.)Am Ende habe ich das
sectionInset
undheaderReferenceSize
abhängig von der Bildschirmgröße eingestellt. Ich habe ungefähr 50 Kombinationen ausprobiert, bis ich Werte gefunden habe, bei denen das Problem nicht mehr auftrat und das Layout visuell akzeptabel war. Es ist sehr schwierig, Werte zu finden, die für beide Bildschirmgrößen geeignet sind.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 behebt.
quelle
Ich habe gerade ein ähnliches Problem mit Zellen festgestellt, die nach dem Scrollen von UICollectionView unter iOS 10 verschwunden sind (unter iOS 6-9 gab es keine Probleme).
Unterklasse von UICollectionViewFlowLayout und überschreibende Methode layoutAttributesForElementsInRect: funktioniert in meinem Fall nicht.
Die Lösung war einfach genug. Derzeit verwende ich eine Instanz von UICollectionViewFlowLayout und setze sowohl itemSize als auch EstimatedItemSize (ich habe zuvor nicht verwendet) und setze sie auf eine Größe ungleich Null. Die tatsächliche Größe wird in der Methode collectionView: layout: sizeForItemAtIndexPath: berechnet.
Außerdem habe ich einen Aufruf der invalidateLayout-Methode aus layoutSubviews entfernt, um unnötiges Neuladen zu vermeiden.
quelle
Ich habe gerade ein ähnliches Problem festgestellt, aber eine ganz andere Lösung gefunden.
Ich verwende eine benutzerdefinierte Implementierung von UICollectionViewFlowLayout mit einem horizontalen Bildlauf. Ich erstelle auch benutzerdefinierte Rahmenpositionen für jede Zelle.
Das Problem, das ich hatte, war, dass [super layoutAttributesForElementsInRect: rect] nicht alle UICollectionViewLayoutAttributes zurückgab, die auf dem Bildschirm angezeigt werden sollten. Bei Aufrufen von [self.collectionView reloadData] würden einige der Zellen plötzlich ausgeblendet.
Am Ende habe ich ein NSMutableDictionary erstellt, das alle bisher gesehenen UICollectionViewLayoutAttributes zwischengespeichert hat und dann alle Elemente enthält, von denen ich weiß, dass sie angezeigt werden sollen.
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { NSArray * originAttrs = [super layoutAttributesForElementsInRect:rect]; NSMutableArray * attrs = [NSMutableArray array]; CGSize calculatedSize = [self calculatedItemSize]; [originAttrs enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * attr, NSUInteger idx, BOOL *stop) { NSIndexPath * idxPath = attr.indexPath; CGRect itemFrame = [self frameForItemAtIndexPath:idxPath]; if (CGRectIntersectsRect(itemFrame, rect)) { attr = [self layoutAttributesForItemAtIndexPath:idxPath]; [self.savedAttributesDict addAttribute:attr]; } }]; // We have to do this because there is a bug in the collection view where it won't correctly return all of the on screen cells. [self.savedAttributesDict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSArray * cachedAttributes, BOOL *stop) { CGFloat columnX = [key floatValue]; CGFloat leftExtreme = columnX; // This is the left edge of the element (I'm using horizontal scrolling) CGFloat rightExtreme = columnX + calculatedSize.width; // This is the right edge of the element (I'm using horizontal scrolling) if (leftExtreme <= (rect.origin.x + rect.size.width) || rightExtreme >= rect.origin.x) { for (UICollectionViewLayoutAttributes * attr in cachedAttributes) { [attrs addObject:attr]; } } }]; return attrs; }
Hier ist die Kategorie für NSMutableDictionary, in der die UICollectionViewLayoutAttributes korrekt gespeichert werden.
#import "NSMutableDictionary+CDBCollectionViewAttributesCache.h" @implementation NSMutableDictionary (CDBCollectionViewAttributesCache) - (void)addAttribute:(UICollectionViewLayoutAttributes*)attribute { NSString *key = [self keyForAttribute:attribute]; if (key) { if (![self objectForKey:key]) { NSMutableArray *array = [NSMutableArray new]; [array addObject:attribute]; [self setObject:array forKey:key]; } else { __block BOOL alreadyExists = NO; NSMutableArray *array = [self objectForKey:key]; [array enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes *existingAttr, NSUInteger idx, BOOL *stop) { if ([existingAttr.indexPath compare:attribute.indexPath] == NSOrderedSame) { alreadyExists = YES; *stop = YES; } }]; if (!alreadyExists) { [array addObject:attribute]; } } } else { DDLogError(@"%@", [CDKError errorWithMessage:[NSString stringWithFormat:@"Invalid UICollectionVeiwLayoutAttributes passed to category extension"] code:CDKErrorInvalidParams]); } } - (NSArray*)attributesForColumn:(NSUInteger)column { return [self objectForKey:[NSString stringWithFormat:@"%ld", column]]; } - (void)removeAttributesForColumn:(NSUInteger)column { [self removeObjectForKey:[NSString stringWithFormat:@"%ld", column]]; } - (NSString*)keyForAttribute:(UICollectionViewLayoutAttributes*)attribute { if (attribute) { NSInteger column = (NSInteger)attribute.frame.origin.x; return [NSString stringWithFormat:@"%ld", column]; } return nil; } @end
quelle
Die obigen Antworten funktionieren bei mir nicht, aber nach dem Herunterladen der Bilder habe ich sie ersetzt
mit
[self.yourCollectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
Um zu aktualisieren und alle Zellen korrekt anzuzeigen, können Sie es versuchen.
quelle
Dies kann etwas spät sein, aber stellen Sie sicher, dass Sie Ihre Attribute
prepare()
nach Möglichkeit festlegen.Mein Problem war, dass die Zellen ausgelegt waren und dann aktualisiert wurden
layoutAttributesForElements
. Dies führte zu einem Flackereffekt, wenn neue Zellen in Sicht kamen.Durch Verschieben der gesamten Attributlogik
prepare
und anschließendes Einstellen wurdeUICollectionViewCell.apply()
das Flimmern beseitigt und eine butterweiche Zelle mit der Anzeige cell erstelltquelle