NSCollectionView可以自动调整其子视图的宽度以显示一列

时间:2010-01-21 08:12:25

标签: cocoa interface-builder nscollectionview

我的NSCollectionView包含CustomViews的集合。最初,它将子视图平铺为列和行,如网格。然后我将IB中的Columns属性设置为1,所以现在它只是在行中一个接一个地显示它们。但是,即使我的CustomView宽度为400px,它设置为自动调整大小,NSCollectionView为400px宽,并且设置为1列,子视图的宽度约为80px。

我知道我可以通过致电来解决这个问题:

CGFloat width = collectionView.bounds.size.width;
NSSize size = NSMakeSize(width, 85);
[collectionView setMinItemSize:size];
[collectionView setMaxItemSize:size];

但是将此代码放在我awakeFromNib的{​​{1}}方法中只会在程序启动时设置正确的宽度。当我调整窗口大小(以及我指定的WindowController自动调整大小)时,CustomViews将保持其初始设置的宽度。

如果需要,我很乐意自己调整子视图的大小,但我对Cocoa很新,似乎找不到任何解释如何做这样的事情的文章。有人能指出我正确的方向吗?

安东尼

8 个答案:

答案 0 :(得分:9)

真正的答案是将maxItemSize设置为0,0(NSZeroSize)。否则,计算它。

[self.collectionView setMaxItemSize:NSZeroSize];

可以在awakeFromNib

中设置

答案 1 :(得分:3)

我知道这是一个非常迟到的回复,但我遇到了同样的问题,并希望我的解决方案可以帮助某人。解决方案是访问封闭滚动视图的边界而不是集合视图本身。所以要解决它,你需要用第一行代替:

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

答案 2 :(得分:2)

我无法使用默认布局 - 但实现自定义布局相当容易:

<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

$route['default_controller'] = "welcome";
$route['404_override'] = '';

然后您需要的只是

/// 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 )
    }
}

答案 3 :(得分:1)

另一个后期 - 我刚刚转而使用NSTableView并通过NSView方法提供delegate

自动化是免费的,一列很容易,并且渲染速度更快。

答案 4 :(得分:0)

假设您希望CollectionViewItem的大小为200x180px,那么您应该设置:

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

你的最大尺寸应该足够大,看起来不错,并提供足够的空间来拉伸以适应collectionView-Width。

如果你有一个固定数量的列,你可以使用(0,0),但如果你想要一个像我想要的动态行数和列数,你应该设置一个固定的最小尺寸和一个更大的最大值.size。

答案 5 :(得分:0)

虽然你可能会得到一个集合视图来表现你想要的行为,但我认为你有一个设计问题

您应该使用NSTableView并将列设置为1,并将其大小设置为除“无”之外的任何内容。 NSTableView用于表格数据,此外它还可以回收单元格,从而为大量项目提供出色的性能提升。 NSCollectionView更像是一个线性布局,它使用垂直滚动来排列网格中的项目。当列号可以动态更改以允许在屏幕上显示更多项目时,它非常有用,通常取决于设备方向和屏幕大小。

答案 6 :(得分:0)

我尝试了这里提出的所有解决方案,但都没有帮助。如果您使用流布局(默认情况下使用),则可以使用以下代码对其进行扩展,并且每次更改都会调用委托的sizeForItem方法

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
    }
}

希望这对某人有帮助,因为我花了两个晚上才找到解决方法

答案 7 :(得分:-4)

Matt Gallagher精彩的博客Cocoa with Love 关于来解决这个问题。本周,他分享了一个单列视图的绑定详细信息,如下所示:

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

下一个条目,他承诺分享其余的实施,这应该可以为您提供所需的信息。

(我应该注意他是直接子类化NSView并重新实现许多NSCollectionView的功能。这似乎很常见;没有多少人喜欢子类化NSCollectionView。)

编辑:似乎他违背了承诺......我们从来没有收到过那篇文章。请参阅下面的tofutim答案。