NSCollectionView loses scrollbars after changing m

2019-08-18 05:21发布

问题:

I have an NSCollectionView with a vertical NSCollectionViewFlowLayout. I display rectangular icons in it.

I also have a slider in the UI, and when that changes, I adjust the minItemSize, which I then use in collectionView:itemForRepresentedObjectAtIndexPath: to create an equally sized NSImageView to the returned NSCollectionViewItem's imageView. Then I reload the view by invoking reloadData.

After that, the view shows the icons in the new size as intended.

The problem is, provided I have more data to show than fits into the current scoll view, that when the General System Preferences are set to Show scroll bars: When scrolling, the scrollbar disappears after reloading the collection view, and trying to scroll with the trackpad leads to a bounce that's telling me that the scroll view thinks that the content is just what's visible, nothing more to scroll.

But as soon as I resize the window, which also resizes the collection view inside, the scrollbars come back.

Curiously, if the System Prefs are set to Show scroll bars: Always, then the issue does not appear and the scrolling always works, and the scrollbars always remain visible.

I've tried a lot of things to trigger the re-calculation of the scroll view, such as invalidating the layout of the collection view's layout, the scroll view itself, its content view, and also tried to set their needsLayout to true. Nothing makes this work.

Update: The potential duplicate (NSCollectionView does not scroll items past initial visible rect), neither the collectionView.setFrameSize: nor the window.setFrame: suggestions work for my case (I tried adding these line before and after reloadData).

Even if I force a resize of the window like this, it doesn't bring the scrollbars back, only a manual dragging of the window edges does:

[self.collectionView.window setFrame:NSInsetRect(self.view.window.frame, 1, 1) display:YES];

Also note that in my case, initially the scrolling works, just not after resizing and reloading.

Another finding: When I call selectItemsAtIndexPaths:scrollPosition: after reloadData, then the scrollbar comes back. But only if I pass a non-empty NSSet for the paths. And since I may not have selected any items, this isn't a permanent solution.

If no other ideas come up, I'll try to make a demo project.

回答1:

I've solved it:

I had to delay the call to reloadData, e.g. by calling it from within the block code of dispatch_async(dispatch_get_main_queue(), ^{ ... });

Before the fix, I did call reloadData right from the setSliderValue: handler, which is bound to the slider's value. It appears that this didn't go well together.