Может ли NSCollectionView автоматически изменять ширину своих вложенных представлений для отображения одного столбца
-
22-09-2019 - |
Вопрос
У меня есть 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
это больше похоже на линейный макет, который упорядочивает элементы в виде сетки с вертикальной прокруткой.Это полезно, когда номер столбца может динамически изменяться, чтобы разрешить отображение большего количества элементов на экране, обычно в зависимости от ориентации устройства и размера экрана.