Может ли NSCollectionView автоматически изменять ширину своих вложенных представлений для отображения одного столбца

StackOverflow https://stackoverflow.com/questions/2107755

Вопрос

У меня есть NSCollectionView который содержит коллекцию CustomViews.Первоначально он разбил вложенные представления на столбцы и строки, как сетку.Затем я устанавливаю Columns свойство в IB равно 1, так что теперь оно просто отображает их один за другим в строках.Однако, даже несмотря на то, что мой CustomView имеет ширину 400 пикселей, он настроен на авторазмер, NSCollectionView имеет ширину 400 пикселей и значение в 1 столбец, вложенные представления отображаются шириной около 80 пикселей.

Я знаю, что могу обойти это, позвонив:

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

Но помещая этот код в awakeFromNib метод моего WindowController задает правильную ширину только при запуске программы.Когда я изменяю размер окна (и NSCollectionView автоматически изменяет размер, как я указал), пользовательские просмотры остаются на своей изначально заданной ширине.

Я рад сам позаботиться об изменении размера вложенных представлений, если потребуется, но я совсем новичок в Cocoa и, похоже, не могу найти никаких статей, объясняющих, как это сделать.Кто-нибудь может указать мне правильное направление?

Энтони

Это было полезно?

Решение

Замечательный блог Мэтта Галлахера Какао с Любовью является о нас чтобы решить эту проблему.На этой неделе он поделился подробностями привязок представления с одним столбцом, подобного тому, о котором идет речь:

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

В следующей записи он обещает поделиться остальной частью реализации, которая должна дать вам то, что вы ищете.

(Я должен отметить, что он напрямую подклассирует NSView и повторно реализует многие функции NSCollectionView.Однако это, кажется, обычное дело;не многим людям нравится создавать подклассы NSCollectionView.)

Редактировать: Похоже, он нарушил свое обещание...мы так и не получили это сообщение.Вместо этого смотрите ответ тофутима ниже.

Другие советы

Истинный ответ заключается в том, чтобы установить maxItemSize равным 0,0(NSZeroSize).В противном случае он вычисляется.

[self.collectionView setMaxItemSize:NSZeroSize];

Это может быть установлено в awakeFromNib.

Я знаю, что это очень поздний ответ, но я столкнулся с той же проблемой и надеюсь, что мое решение кому-нибудь поможет.Решение состоит в том, чтобы получить доступ к границам охватывающего вида прокрутки, а не к самому виду коллекции.Итак, чтобы решить эту проблему, вам нужно заменить первую строку на:

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

Я не смог заставить это работать с макетом по умолчанию, но реализовать пользовательский макет довольно легко:

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

тогда все, что вам нужно, это

var layout=SingleColumnLayout()
collectionView.collectionViewLayout = layout

еще одно запоздалое решение - я только что перешел на использование NSTableView и предоставление NSView по delegate способ.

Авторазмер предоставляется бесплатно, с одним столбцом все просто, и он отображается значительно быстрее.

Допустим, вы хотите, чтобы ваш CollectionViewItem имел размер 200x180 пикселей, тогда вам следует установить:

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

Ваш максимальный размер должен быть достаточно большим, чтобы хорошо выглядеть, и оставлять достаточно места для растяжения, чтобы соответствовать ширине CollectionView.

Если у вас фиксированное количество столбцов, вы, вероятно, можете использовать (0,0), но если вы хотите динамическое количество строк и столбцов, как я хотел..вы должны установить фиксированный минимальный размер и больший максимальный размер.

Хотя вы могли бы заставить представление коллекции вести себя так, как вы хотите, я думаю, у вас проблема с дизайном

Вы должны использовать NSTableView и установите столбцам значение 1, а их размеру - любое, кроме "None". NSTableView предназначен для табличных данных, плюс он может перерабатывать ячейки, что значительно повышает производительность для большого количества элементов. NSCollectionView это больше похоже на линейный макет, который упорядочивает элементы в виде сетки с вертикальной прокруткой.Это полезно, когда номер столбца может динамически изменяться, чтобы разрешить отображение большего количества элементов на экране, обычно в зависимости от ориентации устройства и размера экрана.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top