Puis NSCollectionView AutoResize la largeur de ses sous-vues pour afficher une colonne
-
22-09-2019 - |
Question
J'ai un NSCollectionView
qui contient une collection de CustomViews
. Dans un premier temps, il en mosaïque les sous-vues en colonnes et des lignes comme une grille. Je puis définir la propriété Columns
dans IB 1, maintenant il les affiche juste un après l'autre en rangées. Cependant, même si mon CustomView
est 400px de large, il est mis à AutoResize, le NSCollectionView
est 400px de large, et il est fixé à 1 colonne, les sous-vues sont tirées sur 80px large.
Je sais que je peux contourner ce problème en appelant:
CGFloat width = collectionView.bounds.size.width;
NSSize size = NSMakeSize(width, 85);
[collectionView setMinItemSize:size];
[collectionView setMaxItemSize:size];
Mais mettre ce code dans la méthode awakeFromNib
de mon WindowController
ne définit que la largeur correcte lorsque le programme est lancé. Quand je redimensionnez la fenêtre (et le NSCollectionView
autoresizes comme je l'ai spécifié), les CustomViews restent à leur largeur initialement fixé.
Je suis heureux de prendre soin de redimensionner les sous-vues moi-même si besoin est, mais je suis tout à fait nouveau pour Cocoa et ne peut pas sembler trouver des articles expliquant comment faire une telle chose. Quelqu'un peut-il me diriger dans la bonne direction?
Anthony
La solution
Matt Gallagher blog merveilleux Cocoa avec amour est sur les pour remédier à ce. Cette semaine, il a partagé les détails fixations d'une vue d'une colonne comme celle en question:
http://cocoawithlove.com/2010/03/designing -Voir-avec-bindings.html
entrée suivante, il promet de partager le reste de la mise en œuvre, ce qui devrait vous donner ce que vous cherchez.
(je remarque qu'il est directement et sous-classement NSView réimplémenter de nombreuses fonctions de NSCollectionView Cela semble être commun que,.. Pas beaucoup de gens sont friands de sous-classement NSCollectionView)
Modifier Semble il a rompu sa promesse ... nous n'avons reçu ce poste. Voir la réponse ci-dessous tofutim à la place.
Autres conseils
La vraie réponse consiste à définir la MaxItemSize à 0,0 (NSZeroSize
). Dans le cas contraire, il est calculé.
[self.collectionView setMaxItemSize:NSZeroSize];
Cela peut être réglé dans awakeFromNib
.
Je sais que c'est une réponse très en retard, mais je suis le même problème et espère que ma solution aidera quelqu'un. La solution est d'accéder à des bornes d'enfermer défilante pas de vue collection elle-même. Donc, pour le résoudre, vous devez remplacer la première ligne avec:
CGFloat width = collectionView.enclosingScrollView.bounds.size.width;
Je ne pouvais pas obtenir ce à travailler avec une mise en page par défaut - mais il est assez facile à mettre en œuvre une mise en page personnalisée:
/// 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 )
}
}
tout ce que vous avez besoin est
var layout=SingleColumnLayout()
collectionView.collectionViewLayout = layout
autre fin - je viens d'utiliser un basculé NSTableView
et en fournissant une NSView
par la méthode delegate
Autoresizing est gratuit, une colonne est facile, et il rend massivement plus rapidement.
Disons que vous voulez que votre CollectionViewItem avec une taille de 200x180px, vous devez définir:
[myCollectionView setMinItemSize:NSMakeSize(200, 180)];
[myCollectionView setMaxItemSize:NSMakeSize(280, 250)];
Votre Max-taille doit être assez grand pour bien paraître et de donner suffisamment d'espace pour étirer pour adapter la CollectionView-largeur.
Si vous avez un nombre fixe de colonnes, vous pouvez probablement utiliser (0,0), mais si vous voulez un nombre dynamique de lignes et de colonnes comme je voulais .. vous devez définir une taille minimum fixe et une plus grande max .Size.
Alors que vous pouvez obtenir une vue de collection à se comporter comme vous voulez, je pense que vous avez un problème de conception
Vous devez utiliser une NSTableView
et les colonnes mises à 1 et leur dimensionnement à tout sauf « Aucun ». NSTableView
est destiné aux tableaux de données, plus il peut recycler les cellules qui donne un gain de performances pour une grande quantité d'articles. NSCollectionView
ressemble plus à une disposition linéaire qui organise les éléments dans une grille, avec le défilement vertical. Il est utile lorsque le numéro de colonne peut changer de façon dynamique pour permettre plus d'éléments à afficher à l'écran, généralement en fonction de l'orientation de l'appareil et la taille de l'écran.