O NSCOLLECTIONVIEW AUTORORESize a largura de suas subvisões para exibir uma coluna
-
22-09-2019 - |
Pergunta
eu tenho um NSCollectionView
que contém uma coleção de CustomViews
. Inicialmente, encaixou as subvisões em colunas e linhas como uma grade. Eu então defino o Columns
Propriedade em IB a 1, então agora apenas os exibe um após o outro em linhas. No entanto, mesmo que meu CustomView
tem 400px de largura, está definido para automaticamente, o NSCollectionView
tem 400px de largura e é definido como 1 coluna, as subviews são desenhadas com cerca de 80px de largura.
Eu sei que posso contornar isso ligando:
CGFloat width = collectionView.bounds.size.width;
NSSize size = NSMakeSize(width, 85);
[collectionView setMinItemSize:size];
[collectionView setMaxItemSize:size];
Mas colocando este código no awakeFromNib
método do meu WindowController
Define apenas a largura correta quando o programa é lançado. Quando eu redimenso a janela (e o NSCollectionView
Autorosiza como eu especifiquei), as visualizações personalizadas permanecem na largura inicialmente definida.
Fico feliz em cuidar de redimensionar as subviews, se necessário, mas sou muito novo no cacau e não consigo encontrar nenhum artigo explicando como fazer uma coisa dessas. Alguém pode me apontar na direção certa?
Anthony
Solução
Blog maravilhoso de Matt Gallagher Cacau com amor é cerca de para endereçar isto. Nesta semana, ele compartilhou os detalhes das ligações de uma visão de uma coluna como a em questão:
http://cocoawithlove.com/2010/03/designing-view-with-bindings.html
Na próxima entrada, ele promete compartilhar o restante da implementação, o que deve dar o que você está procurando.
(Devo observar que ele está subclassificando diretamente a NSView e reimplementando muitos dos recursos do NSCOLLECTIONVIEW. Isso parece ser comum; poucas pessoas gostam de subclassem a NSCOLLECTIONVIEW.)
Editar: Parece que ele quebrou sua promessa ... nunca recebemos esse post. Veja a resposta de Tofutim abaixo.
Outras dicas
A verdadeira resposta é definir o maxitemSize para 0,0 (NSZeroSize
). Caso contrário, é calculado.
[self.collectionView setMaxItemSize:NSZeroSize];
Isso pode ser definido em awakeFromNib
.
Eu sei que isso é um muito Resposta tardia, mas tive o mesmo problema e espero que minha solução ajude alguém. A solução é acessar os limites da exibição de rolagem que não encostará a vista da coleção. Então, para resolvê -lo, você precisa substituir a primeira linha por:
CGFloat width = collectionView.enclosingScrollView.bounds.size.width;
Não consegui fazer isso funcionar com um layout padrão - mas é bastante fácil implementar um layout personalizado:
/// 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 )
}
}
Então tudo que você precisa é
var layout=SingleColumnLayout()
collectionView.collectionViewLayout = layout
Outro tarde - eu apenas mudei para usar um NSTableView
e fornecendo um NSView
pelo delegate
método.
Autororesing vem de graça, uma coluna é fácil e torna -se massivamente mais rápido.
Digamos que você queira sua coleçãoViewItem com um tamanho de 200x180px, então você deve definir:
[myCollectionView setMinItemSize:NSMakeSize(200, 180)];
[myCollectionView setMaxItemSize:NSMakeSize(280, 250)];
Seu tamanho máximo deve ser grande o suficiente para parecer bom e dar espaço suficiente para alongar para se ajustar à largura da coleção.
Se você possui um número fixo de colunas, provavelmente poderá usar (0,0), mas se deseja um número dinâmico de linhas e colunas como eu queria. Você deve definir um tamanho minimizado fixo e um max.size maior.
Embora você possa ter uma visão de coleção para se comportar como você quiser, acho que você tem um problema de design
Você deve usar um NSTableView
e defina colunas como 1 e seu dimensionamento para qualquer coisa, menos "nenhum". NSTableView
destina -se a dados tabulares, além de reciclar células, o que oferece um ótimo aumento de desempenho para uma grande quantidade de itens. NSCollectionView
é mais como um layout linear que organiza itens em uma grade, com rolagem vertical. É útil quando o número da coluna pode alterar dinamicamente para permitir que mais itens sejam mostrados na tela, geralmente dependendo da orientação do dispositivo e do tamanho da tela.