具有正交滚动的 NSCollectionView 组合布局具有不正确的标题约束和其他奇怪之处

问题描述 投票:0回答:1

我开始怀疑 macOS 上的 NSCollectionView + Compositional Layout 有很多 bug...😅

我正在使用 NSCollectionView + 组合布局。

我的布局可以在正交滚动部分或更标准的“平铺”部分之间切换。

行为我注意到,当我处于正交滚动模式时,我的节标题具有由具有错误来源的组合布局引擎自动设置的 NSLayoutConstraints。

在此屏幕截图中,我处于正交滚动模式。

您可以看到项目数量较少的部分的部分标题超出了滚动视图的前缘。有趣的是,原点适应滚动视图的宽度。

我的视图越宽,向左的偏移量就越大:

这是一个非正交滚动屏幕截图,其预期标题布局具有正确的原点:

我的标题视图将

translatesAutoresizingMaskIntoConstraints
设置为 false,并在其中使用约束(这些约束是正确的,它只是关闭的滚动视图的起源)。

我读过有关构图布局怪癖的其他问题

  • 使用垂直组似乎可以解决一些布局问题
  • 我在这里不使用估计尺寸
  • 如果我删除内容插入,问题仍然存在
  • 如果我删除背景视图,问题仍然存在(事实上,即使标题不正确,背景视图始终是正确的)

我正在 macOS 13.6.3 上运行 Xcode 15.1,如果这有影响的话,

欢迎任何见解或建议。

我的布局如下:

   func createLayout()
    {
        let config = NSCollectionViewCompositionalLayoutConfiguration()
        config.scrollDirection = .vertical
        config.interSectionSpacing = 16.0
        
        let layout = NSCollectionViewCompositionalLayout(sectionProvider: {
            (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
            
            let snapshot = self.dataSource.snapshot()
            
            let width = layoutEnvironment.container.effectiveContentSize.width
            
            if self.layoutWrap
            {
                return self.mediaLayoutSection(snapshot:snapshot, forEnvironmentWidth: width)
            }
            else
            {
                return self.mediaLayoutSection(snapshot:snapshot, forEnvironmentHeight:150)
            }

        }, configuration: config)
        
        layout.register(OzuBackgroundRoundedView.self, forDecorationViewOfKind: OzuBackgroundRoundedView.kind)
        
        self.collectionView.collectionViewLayout = layout
    }
    
    private  func mediaLayoutSection(snapshot:NSDiffableDataSourceSnapshot<VideoAssetWrapper, SegmentEditViewWrapper>, forEnvironmentHeight:CGFloat) -> NSCollectionLayoutSection
    {
        let itemHeight =  floor( forEnvironmentHeight )
        
        let aspect = 16.0 / 9.0
        let topPadding = 6.0
        let bottomPadding = 6.0
        let leftPadding = 6.0
        let rightPadding = 6.0

        let widthDimension:NSCollectionLayoutDimension = .absolute( (itemHeight * aspect) )
        let heightDimension:NSCollectionLayoutDimension = .absolute( itemHeight )

        let itemSize = NSCollectionLayoutSize(widthDimension: widthDimension,
                                              heightDimension: heightDimension )
        
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = .init(top: topPadding, leading: leftPadding, bottom: bottomPadding, trailing: rightPadding)
        
        let groupSize = NSCollectionLayoutSize(widthDimension: widthDimension,
                                               heightDimension: heightDimension )
        
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .continuous
        section.contentInsets =  NSDirectionalEdgeInsets(top: 6, leading: 6, bottom: 6, trailing:6)
        section.boundarySupplementaryItems = [self.makeSectionHeader()]
        section.decorationItems = [ self.makeBackgroundItem() ]
        section.supplementariesFollowContentInsets = true
        
        return section
    }
    
    func mediaLayoutSection(snapshot:NSDiffableDataSourceSnapshot<VideoAssetWrapper, SegmentEditViewWrapper>, forEnvironmentWidth:CGFloat) -> NSCollectionLayoutSection
    {
        let columnCount = Int( self.layoutSize )
        
        let itemWidth =  floor( forEnvironmentWidth / CGFloat( columnCount ) )
        
        let aspect = 9.0 / 16.0
        let topPadding = 6.0
        let bottomPadding = 6.0
        let leftPadding = 6.0
        let rightPadding = 6.0

        let itemSize = NSCollectionLayoutSize(widthDimension: .absolute( itemWidth ),
                                              heightDimension: .absolute( itemWidth  * aspect ))
        
        let item = NSCollectionLayoutItem(layoutSize: itemSize)
        item.contentInsets = .init(top: topPadding, leading: leftPadding, bottom: bottomPadding, trailing: rightPadding)

        let groupSize = NSCollectionLayoutSize(widthDimension: .absolute( forEnvironmentWidth ),
                                               heightDimension: .absolute( itemWidth * aspect  ) )
        
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
        
        let section = NSCollectionLayoutSection(group: group)
        section.contentInsets =  NSDirectionalEdgeInsets(top: 6, leading: 6, bottom: 6, trailing:6)
        section.boundarySupplementaryItems = [self.makeSectionHeader()]
        section.decorationItems = [ self.makeBackgroundItem() ]
        section.supplementariesFollowContentInsets = true

        return section
    }
        
    
    private func makeSectionHeader() -> NSCollectionLayoutBoundarySupplementaryItem
    {
        let layoutSectionHeaderItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(50))
        let layoutSectionHeaderItem = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: layoutSectionHeaderItemSize, elementKind: VideoAssetHeaderView.kind, alignment: .top)
        
        layoutSectionHeaderItem.pinToVisibleBounds = true
        return layoutSectionHeaderItem
    }
    
    private func makeBackgroundItem() -> NSCollectionLayoutDecorationItem
    {
        let background = NSCollectionLayoutDecorationItem.background(elementKind: OzuBackgroundRoundedView.kind)
        background.contentInsets = NSDirectionalEdgeInsets(top: 6, leading: 6, bottom: 6, trailing:6)
        return background
    }
macos appkit nscollectionview uicollectionviewcompositionallayout diffabledatasource
1个回答
0
投票

因此,有趣的是,这似乎是带有正交滚动的 pinToBounds 的一些奇怪行为。

禁用“固定到边界”可以修复我看到的一些奇怪行为。

© www.soinside.com 2019 - 2024. All rights reserved.