以编程方式使用数据源创建 NSCollectionView

Creating NSCollectionView with datasource programmatically

我正在尝试使用 NSCollectionViewDataSource 以编程方式创建 NSCollectionView

代码很简单:

self.collectionView = [[NSCollectionView alloc] init];
// Add collection view to self.view etc. 
self.collectionView.dataSource = self;
[self.collectionView registerClass:[NSCollectionViewItem class] forItemWithIdentifier:@"test"]
self.collectionView.collectionViewLayout = gridLayout;
[self.collectionView reloadData]

这会导致调用以下方法(如果我没有明确设置 collectionViewLayout 属性,这两个方法也不会被调用):

- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView*)collectionView
- (NSInteger)collectionView:(NSCollectionView*)collectionView numberOfItemsInSection:(NSInteger)section

但是,collectionView:itemForRepresentedObjectAtIndexPath: 从未被调用过。为了确保最后一个数据源方法被调用,我还需要做些什么吗?我已经确保这两个计数调用 return > 0,所以这不是问题。

看来问题实际上是我没有将 NSCollectionView 包装在 NSScrollView 中。如果它没有包含在滚动视图中,这可能与布局不正确有关(因此不会从数据源请求项目)。

过去几天我一直在研究不同的场景,我敢说使用或不使用 NSScrollView 实际上没有什么区别。无论有没有 scrollView,我都遇到了同样的错误和限制。

"old school" 和新奇的 collectionView 之间的选择确实有很大的不同。 "old school" 我的意思是设置 itemPrototype 和 contents 属性,像这样:

    NSCollectionView *collectionView = [[NSCollectionView alloc] init];
    collectionView.itemPrototype = [TBCollectionViewItem new];
    collectionView.content = self.collectionItems;

    NSInteger index = 0;
    for (NSString *title in _collectionItems) {
        NSIndexPath *path = [NSIndexPath indexPathForItem:index inSection:0];
        TBCollectionViewItem *item = [collectionView makeItemWithIdentifier:@"Test" forIndexPath:path];
        item.representedObject = title;
        index++;
    }
    // Plays well with constraints

新学校,大概是这样的:

NSCollectionView *collectionView = [[NSCollectionView alloc] init];
collectionView.identifier = TBCollectionViewIdentifier;

[collectionView registerClass:[TBCollectionViewItem class] forItemWithIdentifier:TBCollectionViewItemIdentifier]; //register before makeItemWithIdentifier:forIndexPath: is called.
TBCollectionViewGridLayout *gridLayout = [TBCollectionViewGridLayout collectionViewGridLayout:NSMakeSize(250, 100)]; //getting the contentSize from the scrollView does not help
collectionView.collectionViewLayout = gridLayout;
collectionView.dataSource = self;

现在,您可能已经注意到 registerClass: 必须在 makeItemWithIdentifier:forIndexPath 之前调用的注释。实际上,这意味着在设置 .dataSource 之前调用 registerClass:,而在您的代码中您首先设置 .dataSource。文档状态:

Although you can register new items at any time, you must not call the makeItemWithIdentifier:forIndexPath: method until after you register the corresponding item.

我希望我可以说通过切换这两行,所有布局问题都将得到解决。不幸的是,我发现 .collectionViewLayout / .dataSource 组合会导致(自动)布局灾难。是否可以通过从 NSCollectionViewGridLayout 切换到 flowLayout 来解决这个问题,我还不确定。