Creating an NSCollectionView Using a Data Source

I am trying to create an NSCollectionView programmatically using an NSCollectionViewDataSource .

The code is very simple:

 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] 

This leads to the following call invocations (unless I set the collectionViewLayout property explicitly, these two invocations are not invoked):

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

However, collectionView:itemForRepresentedObjectAtIndexPath: never called. Is there anything else I need to do to make sure the last data source method is called? I made sure that two calls to count return> 0, so the problem is not the problem.

+2
objective-c cocoa macos nscollectionview
source share
2 answers

So it seems that the problem was that I did not wrap the NSCollectionView in an NSScrollView. This is probably due to incorrect layout (therefore, elements are not requested from the data source) if it is not wrapped as a scroll.

+7
source share

In recent days, I have been working on a different scenario, and I dare say that using NSScrollView, or not, makes almost no difference. With or without scrollView, I encountered the same errors and limitations.

What is of great importance is the choice between the "old school" and the newfangled element of the collection. By “old school,” I mean setting the properties of the ItemPrototype object and content, something like this:

  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 

New school, something like that:

 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; 

Now you may have noticed the comment that registerClass: must be called before makeItemWithIdentifier: forIndexPath. In practice, this means calling registerClass: before installing .dataSource, while in your code you first install .dataSource. Status of documents:

Although you can register new elements at any time, you should not call the makeItemWithIdentifier: forIndexPath: method until you register the corresponding element.

I would like to say that by switching these two lines, all layout problems will be solved. Unfortunately, I found that the combination .collectionViewLayout / .dataSource is a layout catastrophe recipe. Regardless of whether this can be fixed by switching from NSCollectionViewGridLayout to flowLayout, I'm still not sure.

+1
source share

All Articles