0 Replies
      Latest reply on Dec 2, 2019 12:48 AM by balu2005
      balu2005 Level 1 Level 1 (0 points)

        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:

         

        1. I want the items to be scrollable horizontally only without wrapping to the next line

        2. Only NSCollectionViewFlowLayout seems to be capable of telling `NSCollectionView` 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?