14

画像のグリッドを持つ UICollectionView があります。いずれかをタップすると、グリッドが開き、詳細を含むサブビューが表示されます。このような:

このように見えるはずです

UICollectionViewLayoutAttributes を調整し、選択した項目の現在の行の下にあるすべてのセルの transform3D プロパティで変換を設定することにより、UICollectionViewLayout でグリッドを開きます。これは非常にうまく機能し、他のセルとは異なるサイズの別のセルをグリッドに挿入する最初の試みよりもはるかに優れたアニメーションであり、より簡単なアプローチです。

とにかく...ほとんどの場合は機能しますが、継続して使用すると、コレクション ビューに古い画像が表示されます。彼らはゴースト細胞のようなものです。クリックできません。コレクション ビューから適切に削除されていないようです。また、セルの上に配置されているため、タップが妨げられ、煩わしいだけです。このような:

問題はこんな感じ

これらの細胞がこれを行っている理由は何ですか?

編集:追加したいのですが、コレクションビューを非常に速くスクロールした場合にのみ発生すると思います。それでも発生するかどうかをテストするために、独自の UICollectionViewFlowLayout の置き換えを作成しました。します。

EDIT 2: 3D トランスフォームまたはレイアウトは、これとは関係ありません。UICollectionView のバグに違いありません。非常に高速にスクロールし、停止させてから、画面上のビューを照会するだけで悪用できます。セルの数が 2 倍になることがよくありますが、それらは互いに積み重ねられているため非表示になっています。上記の私の実装は、私が行った翻訳のためにそれらを明らかにします。

これにより、パフォーマンスも大幅に低下する可能性があります。

解決策については、私の回答を参照してください。

4

3 に答える 3

14

私の質問の2番目の編集では、これがなぜ起こっているのかを詳しく説明しています。これが私の回避策です。防弾ではありませんが、私の場合は機能します。同様のことが発生した場合は、私のソリューションを微調整できます。

- (void) removeNaughtyLingeringCells {

    // 1. Find the visible cells
    NSArray *visibleCells = self.collectionView.visibleCells;
    //NSLog(@"We have %i visible cells", visibleCells.count);

    // 2. Find the visible rect of the collection view on screen now
    CGRect visibleRect;
    visibleRect.origin = self.collectionView.contentOffset;
    visibleRect.size = self.collectionView.bounds.size;
    //NSLog(@"Rect %@", NSStringFromCGRect(visibleRect));


    // 3. Find the subviews that shouldn't be there and remove them
    //NSLog(@"We have %i subviews", self.collectionView.subviews.count);
    for (UIView *aView in [self.collectionView subviews]) {
        if ([aView isKindOfClass:UICollectionViewCell.class]) {
            CGPoint origin = aView.frame.origin;
            if(CGRectContainsPoint(visibleRect, origin)) {
                if (![visibleCells containsObject:aView]) {
                    [aView removeFromSuperview];
                }
            }
        }
    }
    //NSLog(@"%i views shouldn't be there", viewsShouldntBeThere.count);

    // 4. Refresh the collection view display
    [self.collectionView setNeedsDisplay];    
}

- (void) scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    if (!decelerate) {
        [self removeNaughtyLingeringCells];
    }
}

- (void) scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
    [self removeNaughtyLingeringCells];
}
于 2013-07-18T12:20:24.507 に答える
2

bandejapaisa への簡単な追加コメント: iOS 6 の下でのみ、アニメーション化されたトランジションをぶち壊す癖もあることがわかりましたUICollectionView。元のセルは元の場所に残り、コピーが作成され、コピーがアニメーション化されます。通常はオリジナルの上にありますが、常にではありません。そのため、単純な境界テストでは不十分でした。

UICollectionViewしたがって、次のことを行う のカスタム サブクラスを作成しました。

- (void)didAddSubview:(UIView *)subview
{
    [super didAddSubview:subview];

    //
    // iOS 6 contains a bug whereby it fails to remove subviews, ever as far as I can make out.
    // This is a workaround for that. So, if this is iOS 6...
    //
    if(![UIViewController instancesRespondToSelector:@selector(automaticallyAdjustsScrollViewInsets)])
    {
        // ... then we'll want to wait until visibleCells has definitely been updated ...
        dispatch_async(dispatch_get_main_queue(),
        ^{
            // ... then we'll manually remove anything that's a sub of UICollectionViewCell
            // and isn't currently listed as a visible cell
            NSArray *visibleCells = self.visibleCells;
            for(UIView *view in self.subviews)
            {
                if([view isKindOfClass:[UICollectionViewCell class]] && ![visibleCells containsObject:view])
                    [view removeFromSuperview];
            }
        });
    }
}

明らかに、「これは iOS 6 ですか」というテストをもう少し直接的に行うことができないのは残念ですが、実際のコードのカテゴリに隠されています。

于 2014-03-06T13:32:49.490 に答える
1

bandejapaisa の回答の Swift UICollectionView 拡張バージョン:

extension UICollectionView {

    func removeNaughtyLingeringCells() {

        // 1. Find the visible cells
        let visibleCells = self.visibleCells()
        //NSLog("We have %i visible cells", visibleCells.count)


        // 2. Find the visible rect of the collection view on screen now
        let visibleRect = CGRectOffset(bounds, contentOffset.x, contentOffset.y)
        //NSLog("Rect %@", NSStringFromCGRect(visibleRect))


        // 3. Find the subviews that shouldn't be there and remove them
        //NSLog("We have %i subviews", subviews.count)
        for aView in subviews {
            if let aCollectionViewCell = aView as? UICollectionViewCell {

                let origin = aView.frame.origin
                if (CGRectContainsPoint(visibleRect, origin)) {
                    if (!visibleCells.contains(aCollectionViewCell)) {
                        aView.removeFromSuperview()
                    }
                }

            }
        }

        // 4. Refresh the collection view display
        setNeedsDisplay()
    }
}
于 2016-07-26T07:11:49.537 に答える