我开始怀疑 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
}
因此,有趣的是,这似乎是带有正交滚动的 pinToBounds 的一些奇怪行为。
禁用“固定到边界”可以修复我看到的一些奇怪行为。