19

ここで説明されているのと同じ動作が、この質問UICollectionViewにつながっています。自分で投稿することにしましたが、さらに調査したため、コメントや上記の質問の編集に投稿したくありませんでした。

何が起こるのですか?:

大きなセルが で表示されている場合、コレクション ビューを特定のオフセットまでスクロールするUICollectionViewUICollectionViewFlowLayout、セルが消えます。

別のセルが表示領域に入るまでさらにスクロールすると、消えた/非表示のセルが再び表示されます。

垂直スクロール コレクション ビューと全幅セルでテストしましたが、水平スクロールの同様の設定でも発生することは確かです。

ラージセルとは?:

説明されている動作は、セルがディスプレイの高さの 2 倍よりも高い場合に発生します ( 960.f + 1.f3.5 インチ ディスプレイ、1136.f + 1.f4 インチ ディスプレイ)。

正確には何が起こりますか?:

コレクション ビューのスクロール オフセットがcell.frame.origin.y + displayHeightOfHardwareセルを超えると、非表示プロパティが設定されYES-collectionView:didEndDisplayingCell:forItemAtIndexPath:呼び出されます (たとえば、3.5 インチの iPhoneにscrollingOffset.y到達すると、最初のセルが非表示に変更されます)。481.f

上記のように、次のセルが表示されるまでスクロールすると、非表示のセルが再び表示されます (つまり、hidden プロパティが に変更されますNO)。までスクロールします。

これは、トリプル ディスプレイの高さ ( ) より大きいセルを操作する場合に変化します1441.f/1705.f。これらは同じ動作を示しますが、どれだけ上下にスクロールしても同じままです。

ほかに何か?:

-(BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBoundsreturnにオーバーライドしても状況は修正されませんYES

NOセルが非表示になった後、プログラムで非表示プロパティを設定してセルを強制的に表示することはできません(didEndDisplayingCellたとえば)

それで、質問は何ですか?:

これはバグであると確信しており、UICollectionView/Controller/Cell/LayoutApple に TSI を提出します。しかし、それまでの間:迅速なハッキング ソリューションのアイデアはありますか?

4

4 に答える 4

9

私はこの問題に対して非常に汚い内部的な解決策を持っています:

@interface UICollectionView ()
- (CGRect)_visibleBounds;
@end

@interface MyCollectionView : UICollectionView

@end

@implementation MyCollectionView

- (CGRect)_visibleBounds {
    CGRect rect = [super _visibleBounds];
    rect.size.height = [self heightOfLargestVisibleCell];
    return rect;
}

- (float)heightOfLargestVisibleCell {
    // do your calculations for current max cellHeight and return it 
    return 1234;
}

@end
于 2013-01-10T13:58:55.327 に答える
3

私にはうまくいっているように見える回避策があり、iOSアプリケーションに対するAppleのルールを狂わせてはいけません。

重要なのは、大きなセルの境界が問題であるという観察です。セルの一方の端がスクロール可能なコンテンツ領域の表示可能領域内にあることを確認することで、これを回避しました。明らかに、必要に応じてUICollectionViewFlowLayoutクラスまたはUICollectionViewLayoutをサブクラス化し、contentOffset値を使用してUIScrollViewのどこにいるかを追跡する必要があります。

また、次のことを確認する必要がありました。

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 

YESを返すか、レイアウトが無効であることを示すランタイム例外に直面します。私の場合、大きい方のセルの端を左端にバインドしたままにします。このようにして、これらの大きなセルの誤った境界交差検出を回避できます。

これにより、スクロール時にセルの幅/高さが更新されるときにセルのコンテンツをどのようにレンダリングするかによって、より多くの作業が作成されます。私の場合、セル内のサブビューは比較的単純で、多くの操作を必要としません。

ここで要求されたように私の例ですlayoutAttributesInRect

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
    NSMutableArray* attributes = [NSMutableArray array];
    NSArray *vertical = myVerticalCellsStore.cells;
    NSInteger startRow = floor(rect.origin.y * (vertical.count)/ (vertical.count * verticalViewHeight + verticalViewSpacing * 2));
    startRow = (startRow < 0) ? 0 : startRow;

    for (NSInteger i = startRow; i < vertical.count && (rect.origin.y + rect.size.height >= i * verticalViewHeight); i++) {
        NSArray *horizontals = myHorizontalStore.horizontalCells;
        UICollectionViewLayoutAttributes *verticalAttr = [self layoutAttributesForSupplementaryViewOfKind:@"vertical" atIndexPath:[NSIndexPath indexPathForItem:0 inSection:i]];
        if (CGRectIntersectsRect(verticalAttr.frame, rect)) {
            [attributes addObject:verticalAttr];
        }

        BOOL foundAnElement = NO;
        for (NSInteger j = 0 ; j < horizontals.count; j++) {
            MYViewLayoutAttributes *attr = (MyViewLayoutAttributes *)[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:j inSection:i]];
            if (CGRectIntersectsRect(rect, attr.frame)) {
                [attributes addObject: attr];
                foundAnElement = YES;
            }
            else if (foundAnElement) {
                break;
            }
        }
    }
    return attributes;
}

これは私のサニタイズされたコードです。基本的に、最初のセルはセルの高さに基づいている必要があるかどうかを計算します。私の場合は修正されているので、計算はかなり簡単です。しかし、私の水平要素にはさまざまな幅があります。したがって、内側のループは、実際には、属性配列に含める適切な数の水平セルを見つけることです。そこでCGRectIntersectsRect、セルが交差するかどうかを判断するためにを使用しています。その後、交差点が失敗するまでループが続きます。また、少なくとも1つの水平セルが見つかった場合、ループは中断されます。お役に立てば幸いです。

于 2013-02-08T15:45:02.933 に答える
0

私の解決策は基本的にはジョナサンのものと同じですが、カテゴリ内にあるため、独自のサブクラスを使用する必要はありません。

@implementation UICollectionView (MTDFixDisappearingCellBug)

+ (void)load {
    NSError *error = nil;
    NSString *visibleBoundsSelector = [NSString stringWithFormat:@"%@isib%@unds", @"_v",@"leBo"];

    if (![[self class] swizzleMethod:NSSelectorFromString(visibleBoundsSelector) withMethod:@selector(mtd_visibleBounds) error:&error]) {
        FKLogErrorVariables(error);
    }
}

- (CGRect)mtd_visibleBounds {
    CGRect bounds = [self mtd_visibleBounds]; // swizzled, no infinite loop
    MTDDiscussCollectionViewLayout *layout = [MTDDiscussCollectionViewLayout castedObjectOrNil:self.collectionViewLayout];

    // Don`t ask me why, but there's a visual glitch when the collection view is scrolled to the top and the max height is too big,
    // this fixes it
    if (bounds.origin.y <= 0.f) {
        return bounds;
    }

    bounds.size.height = MAX(bounds.size.height, layout.maxColumnHeight);

    return bounds;
}

@end
于 2013-05-23T18:43:03.810 に答える