7

我正在使用帶有自定義佈局的UICollectionView以網格格式佈局單元。可以有超過50行和50列。滾動發生在垂直和水平方向。目前,我做所有的佈局設置在prepareLayout並將其存儲在陣列:UICollectionView非常慢的自定義佈局

- (void)prepareLayout { 

    NSMutableArray *newLayoutInfo = [[NSMutableArray alloc] init]; 
    NSMutableArray *newLinearLayoutInfor = [[NSMutableArray alloc] init]; 

    NSInteger sectionCount = [self.collectionView numberOfSections]; 
    NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; 

    self.heightForRows = [delegate collectionViewHeightForAllRows]; 

    self.totalWidthsForRows = [[NSMutableArray alloc] init]; 

    for (int i = 0; i < sectionCount; i++) { 
     [self.totalWidthsForRows addObject:[NSNumber numberWithInt:0]]; 
    } 
    for (NSInteger section = 0; section < sectionCount; section++) { 
     NSMutableArray *cellLayoutInfo = [[NSMutableArray alloc] init]; 


     NSInteger itemCount = [self.collectionView numberOfItemsInSection:section]; 

    for (NSInteger item = 0; item < itemCount; item++) { 
     indexPath = [NSIndexPath indexPathForItem:item inSection:section]; 

     UICollectionViewLayoutAttributes *itemAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath]; 
     itemAttributes.frame = [self frameForCellAtIndexPath:indexPath]; 

     [cellLayoutInfo addObject:itemAttributes]; 
     [newLinearLayoutInfor addObject:itemAttributes]; 
    } 
    [newLayoutInfo addObject:cellLayoutInfo]; 
} 
self.layoutInfo = newLayoutInfo; 
self.linearLayoutInfo = newLinearLayoutInfor; 
} 

然後在layoutAttributesForElementsInRect我:

- (NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { 
NSArray *rows = [self.linearLayoutInfo filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(UICollectionViewLayoutAttributes *evaluatedObject, NSDictionary *bindings) { 
    return CGRectIntersectsRect(rect, [evaluatedObject frame]); 
}]]; 

這工作不錯,但它是laggy和神經質,當我有超過50列和50行。這個問題我現在是,我必須設置

-(BOOL)shouldInvalidateLayoutForBoundsChange { 
     return YES; 
} 

這使得準備整個佈局每次界限變化,這不用說,對性能有很大的影響,你可以勉強滾動。這些單元格僅由具有不透明背景的文本組成,因此這裏沒有問題。

我相信我沒有這樣做,並且必須有更好的方法。我在這裏先向您的幫助表示感謝。

+2

您應該使用儀器,看看你是在滾動過程中花費的時間。 – nielsbot 2013-03-02 18:46:15

+0

我建議在元素添加到您的收藏視圖時進行佈局。無需佈置已經存在的元素 - 它們處於正確的位置。如果你這樣做,你可以關閉'shouldInvalidateLayoutForBoundsChange' – nielsbot 2013-03-02 18:48:16

+0

@nielsbot我有補充視圖充當頭,必須始終設置爲collectionview的內容偏移量。這些位於視圖的頂部和側面。如果我打開'shouldInvalidateLayoutForBoundsChange',那麼頭部不再「浮動」它們應該在的位置。有沒有不同的解決方案? – 2013-03-02 19:18:27

回答

0

好的 - 我現在明白了。以下是我的建議:創建3個集合視圖...一個用於列標題(其中每個單元格爲列標題),一個用於行首(每個單元= 1行首)和一個用於單元的集合視圖。然後,當用戶更改任何收集視圖的滾動位置時,根據需要更新其他2個收集視圖的滾動位置。

enter image description here

+0

您應該使用Instruments在滾動期間分析您的應用程序,並查看您花費CPU時間的位置。在主線程上執行任何CPU密集型操作都會導致您的滾動性能下降。 – nielsbot 2013-03-05 23:06:00

+2

我還製作了一個探查器,您可以在繪製/佈局例程中使用,這可能有所幫助:https://github.com/nielsbot/Profiler – nielsbot 2013-03-05 23:06:45

+4

你在開玩笑嗎? 3集合意見?集合視圖旨在用其自定義佈局子類來設計任何種類的UI。創建3個集合視圖僅僅意味着要殺死應用程序的性能。 – 2014-05-16 15:57:37

5
-(BOOL)shouldInvalidateLayoutForBoundsChange { 
     return YES; 
} 

使佈局每次滾動的時間做prepareLayout(),這意味着重計算的東西在準備將導致laggy實踐,使一個可能的方向來解決這個問題是檢查什麼是真正的花費很多時間。一種可能性是裏面有什麼

for (NSInteger section = 0; section < sectionCount; section++) 
{ 
    // generate attributes ... 
} 

爲了生成佈局的屬性。每當它滾動時,每次這種泛化重新開始時,它就會對滾動產生影響,看起來很蠢,笨拙。所以爲了解決這個問題,或者至少弄清楚這不是真的麻煩,我建議在這個佈局算法中設置一個標誌,比如isScrolling,表示佈局需要準備的情況。每當在prepareLayout()檢查標誌,如果它是,那麼我們就會知道,不需要爲循環重新生成所有的屬性,自第一次佈局初始化以來,這些屬性一直存在。

+1

這就是爲什麼您應該在shouldInvalidateLayoutForBoundsChange中實現邏輯以查看佈局是否已失效。返回YES是邪惡的。 – Andy 2014-11-23 14:40:36

9

在定製流佈局我這樣做,它似乎幫助:

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { 
    return !(CGSizeEqualToSize(newBounds.size, self.collectionView.frame.size)); 
} 
+1

這是行不通的?此時它顯示集合視圖已經具有新的大小,因此總是等於newBounds的大小。 – mattyohe 2015-09-08 18:37:55