2016-06-24 17 views
5

Ich kann nicht vertikal und horizontal scrollen, um mit einem benutzerdefinierten Layout für NSCollectionView zu arbeiten. Gemäß den Dokumenten, gebe ich in meiner Unterklasse die `collectionViewContentSize 'zurück und wenn diese zu groß ist, wird das Scrollen automatisch in der umschließenden Bildlaufansicht der Sammlungsansicht aktiviert. Auch wenn ich alle Elemente in einer horizontalen Reihe anordne, ist nur das vertikale Scrollen aktiviert. HierNSCollectionView benutzerdefinierte Layout aktivieren Bildlauf

ist ein Screenshot: http://i.stack.imgur.com/tMbCN.png

Hier ist mein Layout-Code:

import Cocoa 
class Layout: NSCollectionViewLayout { 

var cellSize = CGSize(width: 100, height: 30) 

var cellSpacing: CGFloat = 10 
var sectionSpacing: CGFloat = 20 

private var contentSize = CGSize.zero 
private var layoutAttributes = [NSIndexPath: NSCollectionViewLayoutAttributes]() 


override func prepareLayout() { 
    guard let collectionView = collectionView else { return } 

    let sections = collectionView.numberOfSections 
    guard sections > 0 else { return } 

    contentSize.height = cellSize.height 

    for section in 0..<sections { 
     let items = collectionView.numberOfItemsInSection(section) 
     guard items > 0 else { break } 

     for item in 0..<items { 
      let origin = CGPoint(x: contentSize.width, y: 0) 
      let indexPath = NSIndexPath(forItem: item, inSection: section) 
      let attributes = NSCollectionViewLayoutAttributes(forItemWithIndexPath: indexPath) 
      attributes.frame = CGRect(origin: origin, size: cellSize) 
      layoutAttributes[indexPath] = attributes 

      contentSize.width += cellSize.width + cellSpacing 
     } 
     contentSize.width += sectionSpacing 
    } 
} 

override var collectionViewContentSize: NSSize { 
    return contentSize 
} 

override func layoutAttributesForElementsInRect(rect: NSRect) -> [NSCollectionViewLayoutAttributes] { 

    return layoutAttributes.values.filter { $0.frame.intersects(rect) } 
} 

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> NSCollectionViewLayoutAttributes? { 
    return layoutAttributes[indexPath] 
} 

override func shouldInvalidateLayoutForBoundsChange(newBounds: NSRect) -> Bool { 
    return false 
} 
} 
+0

In 'Überschreibung var collectionViewContentSize', können Sie' contentSize' und 'self.collectionView.frame' (oder assimiliert) drucken? – Larme

+0

contentSize: (22200.0, 30.0) frame: (0.0, 0.0, 438.0, 228.0) – DasNilpferd

+1

Und es funktioniert vertikal, wenn ich mein Layout in eine vertikale Spalte ändere, kann ich bis zum letzten Element blättern. Nur horizontales Scrollen ist immer deaktiviert. – DasNilpferd

Antwort

1

Es ist ein im Grunde Fehler in NSCollectionView. Als Workaround können Sie die scrollDirection-Methode (aus NSCollectionViewFlowLayout) implementieren und NSCollectionViewScrollDirectionHorizontal zurückgeben.

+0

Können Sie ein Beispiel geben? Ich sehe keine 'scrollDirection' Methode als Teil der' NSCollectionView' Delegierten. –

0

Ich habe eine Lösung gefunden. Ich habe eine Unterklasse von NSCollectionView erstellt. Und verwenden Sie diese Unterklasse, um die standardmäßige NSCollectionView zu ersetzen. Ich habe eine Funktion erstellt, um setFrameSize zu überschreiben. Voila!

-(void)setFrameSize:(NSSize)newSize{ 

    if (newSize.width != self.collectionViewLayout.collectionViewContentSize.width) { 

     newSize.width = self.collectionViewLayout.collectionViewContentSize.width; 

    } 

    [super setFrameSize:newSize]; 

    //NSLog(@"setFrameSize%@", CGSizeCreateDictionaryRepresentation(newSize)); 

} 

Während meines Tests wird die setFrameSize aufgerufen werden und ein Mechanismus stellen Sie die Bildgröße auf {0,0} zuerst dann wieder eingestellt die Breite die gleiche Breite wie der Clipview zu machen und die Höhe von dem halten Layout-Inhaltsgröße.

+1

zu Peder: Es ist ein benutzerdefiniertes NSCollectionViewLayout, nicht das NSCollectionViewFlowLayout. Ich glaube nicht, dass Sie NSCollectionViewScrollDirectionHorizontal für ein benutzerdefiniertes NSCollectionViewLayout verwenden können. –

+0

an dckuehn: Danke für die Formatierung. –

+0

Schade, das kann nicht in Swift konvertiert werden :(Hoffen wir, dass der Fehler bald behoben wird. – Ash

4

Dieser Fehler ist noch nicht abgeschlossen. Ich habe Bo Yuan's hässlichen Hack zu Swift konvertiert. (Nichts für ungut, Bo Yuan, es ist nicht DEINE Schuld, dass wir diese schreckliche Umgehungslösung machen müssen! Ich risse immer noch diesen Code raus, sobald es einen offiziellen Fix gibt. Vorläufig wird dies nur meine Entwicklungsbemühungen am Laufen halten .)

Beachten Sie, dass dies unbedingt so schnell wie möglich gehen muss, da es beim Scrollen für jeden einzelnen Frame der Animation aufgerufen wird. Nicht nett. Bitte, bitte, bitte, jemand repariert dieses Problem oder findet eine angemessene Lösung. Nicht horizontal scrollen zu können, ist lächerlich.

+0

Das funktioniert, aber dann kann ich mein Fenster horizontal nicht ändern. :( –

+0

Das funktioniert für mich, außer dass ich die maximale Breite nehme, weil contentSize kleiner als die Ansichtsgrenzen sein kann. Ich kann die Größe des Fensters ändern und in beiden Richtungen scrollen. – Andy

0

Es scheint, dass nur NSCollectionViewFlowLayout in der Lage ist, einen Rahmen zu diktieren, der eine größere Breite als der Rahmen der übergeordneten Bildlaufansichten aufweist.

Die Lösung besteht darin, NSCollectionViewFlowLayout statt NSCollectionViewLayout abzuleiten. Behandeln Sie die Unterklasse wie jede andere Layout-Unterklasse, fügen Sie jedoch die kritische scrollDirection in prepareLayout() hinzu.

Hier ist die minimale Implementierung für ein Layout, das horizontal scrollt und nur alle Elemente nebeneinander platziert.

-(void) prepareLayout 
{ 
    [super prepareLayout]; 
    self.scrollDirection = NSCollectionViewScrollDirectionHorizontal; 
} 

-(NSSize) collectionViewContentSize 
{ 
    NSSize itemSize = self.itemSize; 
    NSInteger num = [self.collectionView numberOfItemsInSection:0]; 
    NSSize contentSize = NSMakeSize((num * itemSize.width) + ((num+1) * self.minimumLineSpacing), NSHeight(self.collectionView.frame)); 
    return contentSize; 
} 

-(BOOL) shouldInvalidateLayoutForBoundsChange:(NSRect)newBounds { return YES; } 

-(NSArray<__kindof NSCollectionViewLayoutAttributes *> *) layoutAttributesForElementsInRect:(NSRect)rect 
{ 
    int numItems = [self.collectionView numberOfItemsInSection:0]; 
    NSMutableArray* attributes = [NSMutableArray arrayWithCapacity:numItems]; 
    for (int i=0; i<numItems; i++) 
    { 
     [attributes addObject:[self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]]]; 
    } 
    return attributes; 
} 

-(NSCollectionViewLayoutAttributes*) layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath 
{ 
    NSSize itemSize = self.itemSize; 
    NSRect fr = NSZeroRect; 
    fr.size = itemSize; 
    fr.origin.y = (NSHeight(self.collectionView.frame) - itemSize.height)/2.0; 
    fr.origin.x = (indexPath.item+1 * self.minimumLineSpacing) + (indexPath.item * itemSize.width); 
    NSCollectionViewLayoutAttributes* attr = [NSCollectionViewLayoutAttributes layoutAttributesForItemWithIndexPath:indexPath]; 
    attr.frame = fr; 
    return attr; 
}