Can NSCollectionView autoresize the width of its subviews to display one column

蓝咒 提交于 2019-11-29 04:07:15

Matt Gallagher's wonderful blog Cocoa with Love is about to address this. This week, he shared the bindings details of a one-column view like the one in question:

http://cocoawithlove.com/2010/03/designing-view-with-bindings.html

Next entry, he promises to share the rest of the implementation, which should give you what you're looking for.

(I should note that he is subclassing NSView directly and re-implementing many of NSCollectionView's features. This seems to be common though; not many people are fond of subclassing NSCollectionView.)

Edit: Seems he broke his promise... we never did receive that post. See tofutim's answer below instead.

tofutim

The true answer is to set the maxItemSize to 0,0(NSZeroSize). Otherwise, it is computed.

[self.collectionView setMaxItemSize:NSZeroSize];

This can be set in awakeFromNib.

Nikita

I know this is a very late response but I got the same problem and hope my solution will help somebody. Solution is to access bounds of enclosing scroll view not of collection view itself. So to solve it you need to replace first line with:

CGFloat width = collectionView.enclosingScrollView.bounds.size.width;

I couldn't get this to work with a default layout - but it is fairly easy to implement a custom layout:

/// Simple single column layout, assuming only one section
class SingleColumnLayout: NSCollectionViewLayout {

    /// Height of each view in the collection
    var height:CGFloat = 100

    /// Padding is wrapped round each item, with double an extra bottom padding above the top item, and an extra top padding beneath the bottom
    var padding = EdgeInsets.init(top: 5, left: 10, bottom: 5, right: 10)

    var itemCount:Int {
        guard let collectionView = collectionView else {
            return 0
        }

        return collectionView.numberOfItems(inSection:0)
    }

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

    override open func layoutAttributesForItem(at indexPath: IndexPath) -> NSCollectionViewLayoutAttributes? {
        let attributes = NSCollectionViewLayoutAttributes(forItemWith: indexPath)
        guard let collectionView = collectionView else {
            return attributes
        }

        let bounds = collectionView.bounds
        let itemHeightWithPadding = height + padding.top + padding.bottom
        let row = indexPath.item

        attributes.frame = NSRect(x: padding.left, y: itemHeightWithPadding * CGFloat(row) + padding.top + padding.bottom , width: bounds.width - padding.left - padding.right , height: height)
        attributes.zIndex = row

        return attributes
    }

    //If you have lots of items, then you should probably do a 'proper' implementation here
    override open func layoutAttributesForElements(in rect: NSRect) -> [NSCollectionViewLayoutAttributes] {
        var attributes = [NSCollectionViewLayoutAttributes]()

        if (itemCount>0){
            for index in 0...(itemCount-1) {
                if let attribute = layoutAttributesForItem(at: NSIndexPath(forItem: index, inSection: 0) as IndexPath) {
                    attributes.append(attribute)
                }
            }
        }

        return attributes
    }

    override open var collectionViewContentSize: NSSize {

        guard let collectionView = collectionView else {
            return NSSize.zero
        }

        let itemHeightWithPadding = height + padding.top + padding.bottom

        return NSSize.init(width: collectionView.bounds.width, height: CGFloat(itemCount) * itemHeightWithPadding + padding.top + padding.bottom )
    }
}

then all you need is

var layout=SingleColumnLayout()
collectionView.collectionViewLayout = layout
Confused Vorlon

another late one - I just switched to using an NSTableView and providing an NSView by the delegate method.

Autoresizing comes for free, one column is easy, and it renders massively faster.

Lets say you want your CollectionViewItem with a size of 200x180px, then you should set:

[myCollectionView setMinItemSize:NSMakeSize(200, 180)];
[myCollectionView setMaxItemSize:NSMakeSize(280, 250)];

Your Max-Size should be big enough to look good and give enough space for stretching to fit the collectionView-Width.

If you have a fixed number of columns, you can probably use (0,0), but if you want a dynamic number of rows and columns like I wanted.. you should set a fixed min-size and a bigger max.size.

Radu Simionescu

While you might get a collection view to behave as you want, I think you have a design problem

You should use a NSTableView and set columns to 1 and their sizing to anything but "None". NSTableView is intended for tabular data, plus it can recycle cells which gives a great performance boost for large amount of items. NSCollectionView is more like a linear layout which arranges items in a grid, with vertical scrolling. It is useful when the column number can change dynamically to allow more items to be shown on screen, usually depending on device orientation and screen size.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!