簡體   English   中英

NSCollectionViewAttributes 未正確應用於自定義 NSFlowLayout 子類

[英]NSCollectionViewAttributes not getting applied correctly with custom NSFlowLayout subclass

我目前正在使用自定義布局處理NSCollectionView 為此,我將NSCollectionViewFlowLayout子類化以頂部對齊我的項目(它們都具有固定寬度,這使得算法非常簡單)。 我現在遇到的問題是,只有我的集合視圖中的前九個項目才能正確顯示,即頂部對齊。

當最初顯示集合視圖時,這前九個項目至少部分可見。 向下滾動集合視圖時出現的其他項目將在沒有任何頂部對齊的情況下繪制,只是垂直居中每行作為NSCollectionViewFlowLayout的默認行為。 通過廣泛的日志記錄,我可以驗證我的 Layout 只提供正確修改為頂部對齊的NSCollectionViewLayoutAttributes

當我調整包含 NSCollectionView 的NSCollectionView的大小時,從而調整集合視圖本身的大小時,它可見部分中的所有項目都會突然正確顯示。

我錯過了什么?

這是我的自定義子類:

#import "MyCollectionViewLayout.h"

@interface MyCollectionViewLayout ()

@property (nonatomic, strong) NSMutableDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *attributesCache;
@property NSInteger numberOfItemsPerRow;
@property NSInteger numberOfItemsTotal;

@end


@implementation MyCollectionViewLayout

- (void)prepareLayout {
    NSLog(@"Preparing layout");
    [super prepareLayout];
    self.itemSize = CGSizeMake(100, 138);
    self.minimumInteritemSpacing = 5;
    self.minimumLineSpacing = 5;
    self.sectionInset = NSEdgeInsetsMake(10, 10, 10, 10);
    self.attributesCache = @{}.mutableCopy;
    self.numberOfItemsTotal = [self.collectionView.dataSource collectionView:self.collectionView numberOfItemsInSection:0];
    
    NSInteger numberOfItemsPerRow = 1;
    CGFloat computedSize = self.itemSize.width;
    CGFloat usableWidth = self.collectionView.frame.size.width - (self.sectionInset.right + self.sectionInset.left);
    repeat: {
        computedSize += self.minimumInteritemSpacing + self.itemSize.width;
        if (computedSize < usableWidth) {
            numberOfItemsPerRow++;
            goto repeat;
        }
    }
    self.numberOfItemsPerRow = numberOfItemsPerRow;
}

#pragma mark NSCollectionViewFlowLayout override

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSLog(@"Getting layout attributes for rect: %f, %f, %f, %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
    NSArray *attributesArray = [super layoutAttributesForElementsInRect:rect].mutableCopy;
    for (int i = 0; i < attributesArray.count; i++) {
        NSCollectionViewLayoutAttributes *attributes = attributesArray[i];
        NSLog(@"Forwarding attribute request for %@", attributes.indexPath);
        attributes = [self layoutAttributesForItemAtIndexPath:attributes.indexPath];
    }
    return attributesArray;
}

- (NSCollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
    if (!self.attributesCache[indexPath]) NSLog(@"");
    NSLog(@"Getting layout attributes for %@", indexPath);
    if (!self.attributesCache[indexPath]) {
        NSLog(@ "Not cached yet, caching full row");
        [self computeAndCacheAttributesForRowContaining:indexPath];
    }
    return self.attributesCache[indexPath];
}

#pragma mark Private instance methods

- (void)computeAndCacheAttributesForRowContaining:(NSIndexPath *)indexPath {
    NSDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *allAttributesInRowByPath = [self getAllAttributesInRowContaining:indexPath];
    CGFloat minY = CGFLOAT_MAX;
    for (NSIndexPath *path in allAttributesInRowByPath) {
        if (allAttributesInRowByPath[path].frame.origin.y < minY) {
            minY = allAttributesInRowByPath[path].frame.origin.y;
        }
    }
    for (NSIndexPath *path in allAttributesInRowByPath) {
        if (indexPath.item == 9) {
            
        }
        NSLog(@"Changing frame for indexPath %@", path);
        NSRect frame = allAttributesInRowByPath[path].frame;
        NSLog(@"Previous y Position: %f", frame.origin.y);
        NSLog(@"New y Position:      %f", minY);
        frame.origin.y = minY;
        allAttributesInRowByPath[path].frame = frame;
    }
    [self.attributesCache addEntriesFromDictionary:allAttributesInRowByPath];
}

- (NSDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *)getAllAttributesInRowContaining:(NSIndexPath *)indexPath {
    NSMutableDictionary<NSIndexPath *, NSCollectionViewLayoutAttributes *> *attributesToReturn = @{}.mutableCopy;
    NSInteger index = indexPath.item;
    NSInteger firstIndex = index - (index % self.numberOfItemsPerRow);
    NSIndexPath *path;
    for (index = firstIndex; (index < firstIndex + self.numberOfItemsPerRow) && (index < self.numberOfItemsTotal); index++) {
        path = [NSIndexPath indexPathForItem:index inSection:indexPath.section];
        [attributesToReturn setObject:[super layoutAttributesForItemAtIndexPath:path].copy forKey:path];
    }
    return attributesToReturn.copy;
}

@end

你缺少attributesArray[i] = attributes; layoutAttributesForElementsInRect:中返回未修改的屬性。

- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
    NSLog(@"Getting layout attributes for rect: %f, %f, %f, %f", rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
    NSMutableArray *attributesArray = [super layoutAttributesForElementsInRect:rect].mutableCopy;
    for (int i = 0; i < attributesArray.count; i++) {
        NSCollectionViewLayoutAttributes *attributes = attributesArray[i];
        NSLog(@"Forwarding attribute request for %@", attributes.indexPath);
        attributes = [self layoutAttributesForItemAtIndexPath:attributes.indexPath];
        attributesArray[i] = attributes; // <---
    }
    return attributesArray;
}

暫無
暫無

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

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