Search code examples
objective-cmacoscocoacore-graphicsnscollectionview

NSCollectionView visibleRect property


The NSCollectionView displays multiple items. I have a Grid like layout.

I need to determine the items that are currently visible.

According to the documentation there is a method

- (NSArray<NSCollectionViewItem *> *)visibleItems;

with the description

The items returned by this method represent the ones that are active and currently being managed by the collection view. This array may contain items that are outside of the collection view’s actual visible rectangle. For example, it may contain items that were recently visible but have since been scrolled out of view. To test whether an item is actually visible, check to see if its frame rectangle intersects the visibleRect of the collection view.

So I need to manually calculate which items are visible based on its frame coordinates and visibleRect of the collectionView. It's fine of course.

However, what bothers me is which coordinates visibleRect returns.

Usually and it agrees with the documentation here if I have lets say

NSImage *img = [[NSImage alloc] initWithContentsOfFile:...];

[imageView setFrame:NSMakeRect(0., -100., 300., 400.)];
[imageView setImage:img];
NSLog(..., [imageView visibleRect]);
NSLog(..., [imageView frame]);

then the visible rectangle will have as expected

x=0
y=100
width = 300
height = 300

And this fully agrees with the documentation.

However, in the case of the NSCollectionView it behaves differently. If I created items and the first item is displayed, then visibleRect will display

x = 0
y = 0

Now if I scroll a little bit down the output will be

x = 0
y = some number > 0

However, I would expect that it should return a different y value. Because

A view's visible rectangle reflects the portion of the contents that are actually displayed, in terms of the view's bounds coordinate system

Assuming that there is no spacing between items and items are identical

x = 0
y = (numItems - 1) * itemHeight

enter image description here

This behavior is not a problem of course. I can use these values to calculate things based on the returned values. I want to understand the reason.

What am I missing?

P.S. Essentially NSCollectionView visibleRect together with frame of its items behaves as if the origin of the coordinate system were in the top left corner with y increasing down and x increasing right.


Solution

  • NSCollectionView uses a flipped coordinate system. See the flipped property of NSView and Flipped Coordinate Systems.