簡體   English   中英

UICollectionView滾動后不刪除舊單元格

[英]UICollectionView not removing old cells after scroll

我有一個帶有圖像網格的UICollectionView。 當您點擊其中一個時,它會打開網格並顯示包含一些詳細信息的子視圖。 像這樣:

假設看起來像這樣

我通過調整UICollectionViewLayoutAttributes並在transform3D屬性上為所選項目的當前行下面的所有單元格設置轉換,在我的UICollectionViewLayout中打開網格。 這非常好用,並且比我第一次嘗試將另一個單元格插入到與其他單元格大小不同的網格中時,它是一種更好的動畫和更簡單的方法。

無論如何......它大部分時間都有效,但在繼續使用之后我會在集合視圖中看到舊圖像。 它們就像幽靈細胞。 我無法點擊它們,就像它們沒有被正確地從集合視圖中移除一樣,並且它們位於單元頂部以防止點擊並且只是令人討厭。 像這樣:

問題看起來像這樣

任何想法為什么這些細胞這樣做?

編輯:我想補充一下,我認為只有當我快速滾動集合視圖時才會發生這種情況。 我已經編寫了自己的UICollectionViewFlowLayout替換來測試它是否仍然存在。 確實如此。

編輯2:3D變換或布局與此無關。 它必須是UICollectionView中的錯誤。 我可以通過快速滾動,讓停止,然后查詢屏幕上的視圖來利用。 細胞數量通常是兩倍,但它們在彼此堆疊時是隱藏的。 我上面的實現揭示了它們,因為我做了翻譯。

這確實會損害性能。

請參閱我的答案以獲得解決方案

我對我的問題的第二次編輯詳細說明了為什么會發生這種情況,這是我的解決方法。 這不是防彈,但它適用於我的情況,如果你遇到類似的東西,你可以調整我的解決方案:

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

對bandejapaisa的一個快速評論:僅在iOS 6下,我發現UICollectionView還有一個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”測試不能更直接,但它隱藏在我的實際代碼中的一個類別中。

一個Swift UICollectionView擴展版本的bandejapaisa的答案:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM