swiftswiftuiappkitnsscrollviewnscollectionview

How can I get scrolling to work for an NSCollectionView hosted in SwiftUI?


I've built an NSCollectionView wrapper using NSViewRepresentable, but it refuses to scroll. The class looks something like this:

final class SwiftNSCollectionView: NSObject, NSViewRepresentable, NSCollectionViewDataSource // etc
{
// ... init ...

    typealias NSViewType = NSCollectionView
    
    func makeNSView(context: Context) -> NSCollectionView {
        let collectionView = NSCollectionView()
        scrollView.documentView = collectionView
        
        updateNSView(collectionView, context: context)
        
        return collectionView
    }
    
    func updateNSView(_ scrollView: NSCollectionView, context: Context) {
        collectionView.dataSource = self
        // ... other collectionView setup
    }

    // ...
}

Typically, NSCollectionView has a built-in NSScrollView.

I've tried:


Solution

  • You can mitigate this by creating an NSScrollView manually.

    1. Update the NSViewType to be NSScrollView.
    2. Update function signatures as required.
    3. Use your existing NSCollectionView as the .documentView of the new scroll view.

    Then you can use your SwiftNSCollectionView directly in SwiftUI code and it will scroll properly without any custom work on your side.

    final class SwiftNSCollectionView: NSObject, NSViewRepresentable, NSCollectionViewDataSource // etc {
        // ... init ...
    
        // No longer NSCollectionView
        typealias NSViewType = NSScrollView
        
        func makeNSView(context: Context) -> NSScrollView {
            // Create an NSScrollView, too!
            let scrollView = NSScrollView()
            let collectionView = NSCollectionView()
            scrollView.documentView = collectionView
            
            updateNSView(scrollView, context: context)
            
            return scrollView
        }
        
        func updateNSView(_ scrollView: NSScrollView, context: Context) {
            // Since we get an NSScrollView, get the child!
            let collectionView = scrollView.documentView as! NSCollectionView
            collectionView.dataSource = self
            // ... other collectionView setup
        }
    
        // ...
    }