8
votes

I have a NSCollectionViewFlowLayout which contains the following:

- (NSSize) itemSize
{
    return CGSizeMake(self.collectionView.bounds.size.width, kItemHeight);
} // End of itemSize

- (CGFloat) minimumLineSpacing
{
    return 0;
} // End of minimumLineSpacing

- (CGFloat) minimumInteritemSpacing
{
    return 0;
} // End of minimumInteritemSpacing

I've tried to ways to make the layout responsive (set the width whenever resized). I've tried adding the following:

[[NSNotificationCenter defaultCenter] addObserver: self
                                         selector: @selector(onWindowDidResize:)
                                             name: NSWindowDidResizeNotification
                                           object: nil];

- (void) onWindowDidResize: (NSNotification*) notification
{
    [connectionsListView.collectionViewLayout invalidateLayout];
} // End of windowDidResize:

And this works fine if I expand the collection view (resize larger). But if I attempt to collapse the view (resize smaller), I get the following exceptions:

The behavior of the UICollectionViewFlowLayout is not defined because:
The item width must be less than the width of the UICollectionView minus the section insets left and right values, minus the content insets left and right values.
The relevant UICollectionViewFlowLayout instance is <TestListLayout: 0x106f70f90>, and it is attached to <NSCollectionView: 0x106f76480>.

Any suggestions on how I can resolve this?

NOTE1: This is macOS and not iOS (even though the error message states UICollectionViewFlowLayout).

NOTE2: Even though I receive the warning/error the layout width works, but I would like to figure out the underlying issue.

3
Does it make any difference if you expand the window first, in other words do these exceptions only occur at a specific window size?Berendschot
@Berendschot, no difference. I've tried from multiple starting sizes.Kyle
So it does occur after you have enlarged the window first?Berendschot
Yes. It occurs both if I enlarge the window first, then shrink. It also occurs if I just shrink without enlarging (ie another launch of the application).Kyle
I'm also struggling with this and a related performance issue calculating item sizes for large sets as they resize the window. (I provide an estimated size but it still seems to hit sizeForItemAtIndexPath for a lot of items.) My worst-case is that I will prevent resizing. Right now I'm trying to figure out if any of the inLiveResize stuff can help.ja41

3 Answers

1
votes

I had the same problem but in my case I resized view. @Giles solution didn't work for me until I changed invalidation context

class MyCollectionViewFlowLayout: NSCollectionViewFlowLayout {

    override func shouldInvalidateLayout(forBoundsChange newBounds: NSRect) -> Bool {
        return true
    }

    override func invalidationContext(forBoundsChange newBounds: NSRect) -> NSCollectionViewLayoutInvalidationContext {
       let context = super.invalidationContext(forBoundsChange: newBounds) as! NSCollectionViewFlowLayoutInvalidationContext
       context.invalidateFlowLayoutDelegateMetrics = true
       return context
    }
}

Hope it helps someone as it took me couple of evenings to find solution

0
votes

This is because you are using the didResize event, which is too late. Your items are too wide at the moment the window starts to shrink. Try using:

func shouldInvalidateLayout(forBoundsChange newBounds: NSRect) -> Bool {
    return true
}

...when overriding flow layout, to get everything recalculated.

0
votes

The source code I posted in the question works fine as of macOS 10.14 with no issues. I added the following to my window which displays the collection view.

// Only Mojave and after is resizable. Before that, a full sized collection view caused issues as listed
// at https://stackguides.com/questions/48567326/full-width-nscollectionviewflowlayout-with-nscollectionview
if(@available(macOS 10.14, *))
{
    self.window.styleMask |= NSWindowStyleMaskResizable;
} // End of macOS 10.14+