79

私はUICollectionViewFLowLayout を持っています。ほとんどの場合、期待どおりに動作しますが、セルの 1 つが適切にラップされないことがあります。たとえば、3 行目の最初の「列」にあるセルは、実際には 2 行目の末尾にあり、あるべき場所に空のスペースがあるだけです (下の図を参照)。このルージュ セルは左側しか見えず (残りは切り取られています)、本来あるべき場所は空になっています。

これは常に発生するわけではありません。必ずしも同じ行ではありません。それが発生したら、上にスクロールしてから戻ることができ、セルは自動的に修正されます。または、セルを押して (プッシュで次のビューに移動します)、ポップバックすると、セルが間違った位置に表示され、正しい位置にジャンプします。

スクロール速度により、問題の再現が容易になるようです。ゆっくりスクロールすると、セルが時々間違った位置に表示されることがありますが、すぐに正しい位置にジャンプします。

セクションインセットを追加したときに問題が発生しました。以前は、セルがコレクションの境界に対してほぼフラッシュしていました (インセットがほとんど、またはまったくない) が、問題に気づきませんでした。しかし、これはコレクション ビューの左右が空であることを意味していました。つまり、スクロールできませんでした。また、スクロール バーが右に揃っていませんでした。

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

左右のセクションのインセットが原因で問題が発生していると思います...しかし、値が間違っている場合、動作が一貫していると予想されます。これは Apple のバグなのだろうか?あるいは、これはインセットの蓄積または類似の原因によるものかもしれません。

問題と設定の図


フォローアップ:以下のニックによるこの回答を 2 年以上問題なく使用しています (その回答に穴があるかどうか疑問に思っている場合に備えて、まだ見つかっていません)。よくやったニック。

4

12 に答える 12

95

UICollectionViewFlowLayout の layoutAttributesForElementsInRect の実装にバグがあり、セクション インセットが関係する特定のケースで、単一のセルに対して 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 が根本原因を修正したときに問題が発生することはありません。

于 2012-11-14T23:55:31.473 に答える
8

これをコレクションビューを所有するviewControllerに入れます

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}
于 2014-06-03T08:48:32.770 に答える
7

iPhone アプリケーションで同様の問題を発見しました。Apple dev フォーラムを検索すると、この適切なソリューションが得られました。これは私の場合に機能し、おそらくあなたの場合にも機能します。

サブクラス化UICollectionViewFlowLayoutし、オーバーライドshouldInvalidateLayoutForBoundsChangeして return にしYESます。

//.h
@interface MainLayout : UICollectionViewFlowLayout
@end

//.m
#import "MainLayout.h"
@implementation MainLayout
-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds{
    return YES;
}
@end
于 2012-10-31T20:06:06.977 に答える
7

Nick Snyder の回答の Swift バージョン:

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 }
    }
}
于 2015-07-03T12:06:41.903 に答える
5

マージンのインセットを使用した基本的なグリッドビュー レイアウトでも、この問題が発生しました。今のところ私が行った限定的なデバッグは- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect、UICollectionViewFlowLayout サブクラスに実装し、スーパークラスの実装が返すものをログに記録することであり、問​​題を明確に示しています。

- (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;
}

実装する- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingItemAtIndexPath:(NSIndexPath *)itemIndexPathことで、itemIndexPath.item == 30 の間違った値を返すように見えることもわかります。これは、グリッドビューの 1 行あたりのセル数の 10 倍ですが、それが関連しているかどうかはわかりません。

- (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;
}

さらにデバッグする時間がないため、今のところ回避策として、コレクションビューの幅を左右のマージンと同じ量だけ減らします。まだ全幅が必要なヘッダーがあるため、コレクションビューで clipsToBounds = NO を設定し、左右のインセットも削除しましたが、うまくいくようです。ヘッダー ビューが所定の位置にとどまるようにするには、ヘッダー ビューの layoutAttributes を返す役割を担うレイアウト メソッドで、フレームのシフトとサイズ変更を実装する必要があります。

于 2012-10-17T09:28:29.697 に答える
4

Apple にバグレポートを追加しました。私にとってうまくいくのは、bottom sectionInset を top inset よりも小さい値に設定することです。

于 2012-11-08T13:26:03.930 に答える
3

私は iPhone で同じセル交換の問題を経験していたUICollectionViewFlowLayoutので、あなたの投稿を見つけてよかったです。iPad で問題が発生していることは承知していますが、UICollectionView. だからここに私が見つけたものがあります。

sectionInsetがその問題に関連していることを確認できます。それに加えてheaderReferenceSize、セルが置換されているかどうかにも影響があります。(原点を計算するために必要なので、これは理にかなっています。)

残念ながら、異なる画面サイズであっても考慮する必要があります。これら 2 つのプロパティの値をいじってみると、特定の構成が両方 (3.5 インチと 4 インチ) で機能するか、いずれも機能しないか、または画面サイズの 1 つだけで機能することがわかりました。通常、それらのどれもありません。(境界が変化するため、これも理にかなっていUICollectionViewます。そのため、網膜と非網膜の間の不一致は経験しませんでした。)

画面サイズに応じてsectionInsetandを設定することになりました。headerReferenceSize問題が発生しなくなり、レイアウトが視覚的に受け入れられる値を見つけるまで、約 50 の組み合わせを試しました。両方の画面サイズで機能する値を見つけるのは非常に困難です。

要約すると、値をいじって、さまざまな画面サイズでこれらを確認し、Apple がこの問題を修正することをお勧めします。

于 2012-10-29T17:50:25.860 に答える
3

iOS 10で UICollectionView をスクロールした後にセルが消えるという同様の問題が発生しました (iOS 6-9 では問題ありません)。

UICollectionViewFlowLayout のサブクラス化とメソッド layoutAttributesForElementsInRect: のオーバーライドは、私の場合は機能しません。

解決策は簡単でした。現在、UICollectionViewFlowLayout のインスタンスを使用し、itemSize と EstimatedItemSize の両方を設定し (以前は EstimatedItemSize を使用していませんでした)、ゼロ以外のサイズに設定しています。実際のサイズは collectionView:layout:sizeForItemAtIndexPath: メソッドで計算しています。

また、不必要なリロードを避けるために、layoutSubviews から invalidateLayout メソッドの呼び出しを削除しました。

于 2016-10-31T09:44:58.140 に答える
0

これは少し遅いかもしれませんが、prepare()可能であれば属性を設定していることを確認してください。

私の問題は、セルがレイアウトされてから更新されることでしたlayoutAttributesForElements。これにより、新しいセルが表示されたときにちらつき効果が発生しました。

すべての属性ロジックを に移動し、prepareそれらを設定することでUICollectionViewCell.apply()、ちらつきがなくなり、滑らかなセル表示が作成されました

于 2018-05-04T21:37:17.907 に答える