2013-10-22 4 views
7

Ich sehe ein mysteriöses Verhalten von UICollectionView mit einem benutzerdefinierten Layout (Unterklasse von UICollectionViewLayout) beim Drehen des Geräts.UICollectionView-Schnittstelle Rotation mit benutzerdefinierten Layout

Ich habe eine einfache horizontal scrollende Reihe von Zellen. Wenn das Gerät von Hochformat auf Querformat gedreht wird, werden zusätzliche Zellen sichtbar, die vorher nicht sichtbar waren, und die Animation dieser erscheinenden Zellen ist falsch (es verwendet den bekannten Ghosting-Effekt, der meiner Meinung nach eine Art Standardanimationseffekt für die Sammelansicht darstellt) Layouts). Beachten Sie die Zelle auf ganz links in dieser Animation erscheinen:

UICollectionViewRotationGhosting

Einige Informationen über das benutzerdefinierte Layout-Setup:

  • shouldInvalidateLayoutForBoundsChange: kehrt YES.
  • In layoutAttributesForItemAtIndexPath: werden die Attribute in einem Dictionary zwischengespeichert, wenn sie nicht bereits erstellt wurden.
  • In layoutAttributesForElementsInRect: berechne ich, welche Zellen von Hand sichtbar sein sollten, und zwecke ihre centre Eigenschaft jedes Mal leicht, bevor sie ihre Attribute zurückgibt.

Ich habe den folgenden Code dann mit dem Anfang/endgültigen Layout zu behandeln Attribute:

- (void)prepareForAnimatedBoundsChange:(CGRect)oldBounds 
{ 
    [super prepareForAnimatedBoundsChange:oldBounds]; 
    self.animatingBoundsChange = YES; 
} 

- (void)finalizeAnimatedBoundsChange 
{ 
    [super finalizeAnimatedBoundsChange]; 
    self.animatingBoundsChange = NO; 
} 

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPath 
{ 
    if (self.animatingBoundsChange) { 
     // If the view is rotating, appearing items should animate from their current attributes (specify `nil`). 
     // Both of these appear to do much the same thing: 
     //return [self layoutAttributesForItemAtIndexPath:itemIndexPath]; 
     return nil; 
    } 
    return [super initialLayoutAttributesForAppearingItemAtIndexPath:itemIndexPath]; 
} 

- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingItemAtIndexPath:(NSIndexPath *)itemIndexPath 
{ 
    if (self.animatingBoundsChange) { 
     // If the view is rotating, disappearing items should animate to their new attributes. 
     return [self layoutAttributesForItemAtIndexPath:itemIndexPath]; 
    } 
    return [super finalLayoutAttributesForDisappearingItemAtIndexPath:itemIndexPath]; 
} 

Es scheint mir, dass das ursprüngliche Layout für die neu erscheinende Zelle Attribute es irgendwie nicht richtig sind (endet schließlich an der richtigen Stelle). Aber wenn ich die center Eigenschaft der Layout-Attribute protokolliert, die von der initalLayout... Methode zurückgegeben werden, sieht alles korrekt aus - alle gleichmäßig entlang der horizontalen Achse verteilt.

Das einzige Unterscheidungsmerkmal der Zelle, die nicht ordnungsgemäß animiert ist, ist, dass ihre Zelle nicht im Array [collectionView visibleCells] zurückgegeben wird, wenn die Methode aufgerufen wird. Die vorangestellte layoutAttributesForElementsInRect: identifiziert korrekt, dass ihre Layout-Attribute jedoch benötigt werden.

Also, was ist los? Ein paar Einblicke in das, was unter der Motorhaube passiert, wären so hilfreich ... UICollectionView scheint wie eine massive Blackbox.

+0

http://stackoverflow.com/questions/12649271/what-is-the-best-best-way-to-disable-cross-fades- on-uicollectionview-uicollectio? rq = 1 –

+0

Wenn iOS erkennt, dass ein Übergang nicht reibungslos erfolgen kann, dh dieses Szenario, wird eine Überblendungsanimation für alle Zellen verwendet, die mit vorhandenen Zellen kollidieren. Dies ist im WWDC-Video auf UICollectionViews in iOS7 dokumentiert. – Tim

+0

@Arun_k Diese Frage scheint für diesen nicht relevant zu sein - sie fragen nach der Klärung, warum 'initial/finalLayout ...'werden bei der Rotation aufgerufen, und tatsächlich bestätigen sie, dass das Hinzufügen von Code wie oben die Crossfade-Animation verhindert. Diese Frage bezieht sich auf zusätzliche Zellen, die nach einer animierten Bereichsänderung präsentiert werden. – Stuart

Antwort

0

Aufbauend auf the answer that Arun_k linked to scheint es, als ob Sie etwas anderes als initialLayoutAttributesForAppearingItemAtIndexPath: neben nil für die neue Zelle, die erscheint, zurückgeben müssen. nil funktioniert für die Zellen, die bereits auf dem Bildschirm angezeigt werden, aber möglicherweise nicht die richtige Antwort für eine neue Zelle. Vielleicht können Sie mit einem festen UICollectionViewLayoutAttributes Wert für alle Zellen in dieser Methode herumspielen, um zu sehen, ob es das Animationsverhalten der neu eingefügten Zelle ändert und dann von dort weitergeht.

Diese Frage wirft noch mehr Licht auf dieses Problem: initialLayoutAttributesForAppearingItemAtIndexPath fired for all visible cells, not just inserted cells

+0

Danke für die Antwort. Leider, wie ich in meiner Frage sagte, macht die Rückgabe eines Nicht-Null-Wertes ('[self layoutAttributesForItem ...]') keinen Unterschied, obwohl die Protokollierung der zurückgegebenen Werte die korrekte Anfangsposition für alle Zellen anzeigt, einschließlich der neu erscheinende Zelle. Ich werde wie vorgeschlagen spielen und sehen, ob ich mehr herausfinden kann. – Stuart