I'm implementing an application for macOS in which I use an NSCollectionView
as a sort of timeline. For this I use a custom subclass of NSCollectionViewFlowLayout
for the following reasons:
- I want the items to be scrollable horizontally only without wrapping to the next line
- Only
NSCollectionViewFlowLayout
seems to be capable of tellingNSCollectionView
to not scroll vertically (inspiration from here)
All of this works smoothly, however: I'm now trying to implement drag & drop reordering of the items. This also works, but I noticed that the inter item gap indicator (blue line) is not being displayed properly, even though I do return proper sizes. I calculate them as follows:
override func layoutAttributesForInterItemGap(before indexPath: IndexPath) -> NSCollectionViewLayoutAttributes?
{
var result: NSCollectionViewLayoutAttributes? = nil
// The itemLayoutAttributes dictionary is created in prepare() and contains
// the layout attributes for every item in the collection view
if indexPath.item < itemLayoutAttributes.count
{
if let itemLayout = itemLayoutAttributes[indexPath]
{
result = NSCollectionViewLayoutAttributes(forInterItemGapBefore: indexPath)
result?.frame = NSRect(x: itemLayout.frame.origin.x - 4, y: itemLayout.frame.origin.y, width: 3, height: itemLayout.size.height)
}
}
else
{
if let itemLayout = itemLayoutAttributes.reversed().first
{
result = NSCollectionViewLayoutAttributes(forInterItemGapBefore: indexPath)
result?.frame = NSRect(x: itemLayout.value.frame.origin.x + itemLayout.value.frame.size.width + 4, y: itemLayout.value.frame.origin.y, width: 3, height: itemLayout.value.size.height)
}
}
return result
}
Per documentation the indexPath
passed to the method can be between 0 and the number of items in the collection view including if we're trying to drop after the last item. As you can see I return a rectangle for the inter item gap indicator that should be 3 pixels wide and the same height as an item is.
While the indicator is displayed in the correct x-position with the correct width, it is only 2 pixels high, no matter what height I pass in.
How do I fix this?
NB: If I temporarily change the layout to NSCollectionViewFlowLayout
the indicator displays correctly.
I'm overriding the following methods/properties in NSCollectionViewFlowLayout
:
- prepare()
- collectionViewContentSize
- layoutAttributesForElements(in rect: NSRect) -> [NSCollectionViewLayoutAttributes]
- layoutAttributesForItem(at indexPath: IndexPath) -> NSCollectionViewLayoutAttributes?
- shouldInvalidateLayout(forBoundsChange newBounds: NSRect) -> Bool
- layoutAttributesForInterItemGap(before indexPath: IndexPath) -> NSCollectionViewLayoutAttributes?