NSCollectionViewAttributes неправильно применяются с пользовательским подклассом NSFlowLayout

В настоящее время я работаю над пользовательским макетом. Для этой цели я создал подклассы, чтобы выровнять мои элементы по верхнему краю (все они имеют фиксированную ширину, что сделало алгоритм довольно простым). Проблема, с которой я столкнулся сейчас, заключается в том, что только первые девять элементов в моем представлении коллекции отображаются правильно, то есть выровнены по верхнему краю.

Эти первые девять элементов по крайней мере частично видны при первоначальном отображении представления коллекции. Другие элементы, которые появляются при прокрутке представления коллекции, будут отображаться без какого-либо выравнивания по верхнему краю, а только с центрированием по вертикали для каждой строки, как поведение по умолчанию NSCollectionViewFlowLayout. С помощью подробного ведения журнала я мог убедиться, что мой макет обеспечивает только NSCollectionViewLayoutAttributesправильно изменен для выравнивания по верхнему краю.

Когда я изменяю размер окна, содержащего 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

1 ответ

Ты пропускаешь 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;
}
Другие вопросы по тегам