swift - 如何滚动才能在 SwiftUI 中托管的 NSCollectionView 上工作?

标签 swift swiftui appkit nsscrollview nscollectionview

我使用 NSViewRepresentable 构建了一个 NSCollectionView 包装器,但它拒绝滚动。该类看起来像这样:

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
    }

    // ...
}

通常,NSCollectionView 有一个内置的 NSScrollView。

我已经尝试过:

  • 没有包装器 - NSCollectionView 根本不滚动。

  • 将这个 SwiftNSCollectionView 包装在 SwiftUI ScrollView 中,但这会导致两个问题:

    • NSCollectionView 的高度折叠为 0(我可以使用 GeometryReader 来解决这个问题)
    • NSCollectionView 不想扩展到其所有对象的高度(这是有道理的,因为它虚拟化了它们)
  • 使用具有正交滚动方向的 NSCollectionViewCompositionalLayoutConfiguration(hacky):

    let section = NSCollectionLayoutSection(group: group)
    section.orthogonalScrollingBehavior = .continuous
    
    // If the "official" scroll direction is horizontal,
    // then the orthogonal direction becomes vertical,
    // and we can scroll our one section 😈
    let configuration = NSCollectionViewCompositionalLayoutConfiguration()
    configuration.scrollDirection = .horizontal
    

    但这似乎搞乱了键盘输入:在一定数量的元素之后,元素之间的箭头键要么完全停止工作,要么移动到完全错误的元素。看起来像是某种虚拟化错误。

最佳答案

您可以通过手动创建 NSScrollView 来缓解此问题。

  1. NSViewType 更新为 NSScrollView
  2. 根据需要更新函数签名。
  3. 使用现有的 NSCollectionView 作为新 ScrollView 的 .documentView

然后,您可以直接在 SwiftUI 代码中使用 SwiftNSCollectionView,它会正确滚动,无需您进行任何自定义工作。

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
    }

    // ...
}

关于swift - 如何滚动才能在 SwiftUI 中托管的 NSCollectionView 上工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65457831/

相关文章:

objective-c - 在 10.10 Yosemite 中禁用/自定义 NSPopUpButton 动画

ios - 动画切换 CollectionViewLayout

swift - Core Graphics 替代 UIImage/NSImage 文件表示

SwiftUI:设置工作表呈现 View 的背景颜色

swift - `Animation` 案例 (SwiftUI) 的长度是多少?

swift - 使用 SwiftUI 时调整 NSSplitViewController 的大小

ios - UITableViewCell 不遵守取决于内容的约束

ios - 在 SwiftUI 中监听 AVPlayer timeControlStatus 的变化

macos - OSX中是否有等效于UIActivityViewController的东西?

cocoa - NSNumberFormatter 不允许输入十进制数字