1. ホーム
  2. ios

UICollectionViewのflowLayoutでセルが正しく折り返されない件

2023-08-02 07:47:08

質問

私は UICollectionView をFLowLayoutで表示しています。ほとんどの場合、期待通りに動作しますが、時々、セルの1つが適切にラップされません。例えば、3行目の最初の列の上にあるはずのセルが、実際には2行目で末尾になり、あるべき場所に空白ができます(下図を参照)。このルージュのセルは左側しか見えず (残りは切り取られています)、あるべき場所には何もありません。

この現象は一貫して発生するわけではなく、常に同じ行に発生するわけではありません。一度発生したら、上にスクロールしてから戻ると、セルはそれ自体で修正されます。または、セルを押して (これにより、プッシュで次のビューに移動します)、ポップバックすると、セルが不正な位置にあり、その後、正しい位置にジャンプします。

スクロール速度は、問題を再現しやすくしているようです。ゆっくりスクロールすると、まだ時々間違った位置にあるセルが見えますが、その後すぐに正しい位置にジャンプします。

問題は、セクションの挿入を追加したときに始まりました。以前は、セルをコレクション境界とほぼ同じ高さに置いていたので (ほとんど、またはまったくインセットを使用せず)、問題に気づきませんでした。しかし、これでは、コレクション ビューの右側と左側が空白になってしまいます。つまり、スクロールできないのです。また、スクロール バーは右側と同じ高さにありませんでした。

この問題は、シミュレータと iPad 3 の両方で発生させることができます。

左右のセクションのインセットが原因で問題が起きているのでしょうね...。しかし、値がおかしいのであれば、動作は一定になると思うのですが。もしかしてAppleのバグなんでしょうかね?それとも、インセットなどの積み重ねが原因なのでしょうか。


フォローアップ : 私はこれまで この回答 を2年以上使っていますが、問題なく使えています(この答えに穴がないかどうか気になる人がいるかもしれませんが、私はまだ見つけていません)。よくやった、ニック。

どのように解決するのですか?

UICollectionViewFlowLayout の layoutAttributesForElementsInRect の実装にバグがあり、セクション インセットを含む特定のケースで、1 つのセルに対して 2 つの属性オブジェクトを返すことがあります。返された属性オブジェクトの1つは無効(コレクションビューの境界外)であり、もう1つは有効です。下記はUICollectionViewFlowLayoutのサブクラスで、コレクションビューの境界外のセルを除外することによって問題を解決しています。

// 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

参照 この .

他の回答では、shouldInvalidateLayoutForBoundsChangeからYESを返すことを提案していますが、これは不必要な再計算を引き起こし、問題を完全に解決することさえできません。

私の解決策はバグを完全に解決し、Apple が根本的な原因を修正したときに、何の問題も発生しないはずです。