如何为 UICollectionViewCompositionalLayout 中的不同部分设置多个背景视图

Posted

技术标签:

【中文标题】如何为 UICollectionViewCompositionalLayout 中的不同部分设置多个背景视图【英文标题】:How to set up Multiple Background View for different Sections in UICollectionViewCompositionalLayout 【发布时间】:2020-11-26 18:20:04 【问题描述】:

我正在尝试为我的部分提供不同的背景颜色/图像,但发现很难在 createCompositionalLayout() 中设置两个不同的背景视图。

下面是两个背景视图组件和部分。在布局创建方法中注册类/nib 的示例有很多,但这只是为所有部分创建一个背景视图。

在 createCompositionalLayout() 中有一个用于返回 NSCollectionLayoutSection(部分)的开关,但要为每个部分返回已注册的背景视图布局是我的障碍。

   func createCompositionalLayout() -> UICollectionViewLayout 
        let layout = UICollectionViewCompositionalLayout  sectionIndex, layoutEnvironment in
            guard let sectionKind = SectionBack(rawValue: sectionIndex) else  return nil 
            let section = self.sections[sectionIndex]
            switch section.type 
            case "mediumTable":
                return self.createMediumTableSection(using: section)
            case "smallTable":
                return self.createSmallTableSection(using: section)
            default:
                return self.createFeaturedSection()
            
        
        return layout
    

**Red backgroundview**
let backgroundItem = NSCollectionLayoutDecorationItem.background(elementKind: "background")
    let backgroundInset: CGFloat = 8
    backgroundItem.contentInsets = NSDirectionalEdgeInsets(top: backgroundInset, leading: 
backgroundInset, bottom: backgroundInset, trailing: backgroundInset)
    layoutSection.decorationItems = [backgroundItem]
    let layout = UICollectionViewCompositionalLayout(section: layoutSection)
    layout.register(RedBackgroundSupplementaryView.self, forDecorationViewOfKind:     
"background")

func createMediumTableSection(using section: Section) -> NSCollectionLayoutSection 
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(0.33))

    let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
    layoutItem.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 5, bottom: 0, trailing: 5)

    let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.93), heightDimension: .fractionalWidth(0.55))
    let layoutGroup = NSCollectionLayoutGroup.vertical(layoutSize: layoutGroupSize, subitems: [layoutItem])

    let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
    layoutSection.orthogonalScrollingBehavior = .groupPagingCentered

    let layoutSectionHeader = createSectionHeader()
    layoutSection.boundarySupplementaryItems = [layoutSectionHeader]

    return layoutSection


func createSmallTableSection(using section: Section) -> NSCollectionLayoutSection 
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(0.2))
    let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
    layoutItem.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 20, bottom: 0, trailing: 0)

    let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.93), heightDimension: .estimated(200))
    let layoutGroup = NSCollectionLayoutGroup.vertical(layoutSize: layoutGroupSize, subitems: [layoutItem])

    let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
    let layoutSectionHeader = createSectionHeader()
    layoutSection.boundarySupplementaryItems = [layoutSectionHeader]

    return layoutSection

【问题讨论】:

【参考方案1】:

问题出在这对线:

layout.register(RedBackgroundSupplementaryView.self, forDecorationViewOfKind:"background")
layout.register(BlackBackgroundSupplementaryView.self, forDecorationViewOfKind:"background")

你不能同时拥有它。 kind 字符串是您将如何识别您想要的:

let backgroundItem = NSCollectionLayoutDecorationItem.background(elementKind: "background")

但是你只有一个kind 字符串。您的第二个注册出现并取代了第一个。您需要使用两种不同的背景颜色注册两种不同的装饰视图类型。

【讨论】:

好的,假设我只有一个注册类,对于当前设置的背景视图,有没有办法为一个部分而不是整个布局实现它? 不要给其他部分任何装饰? 意思是如何使用我拥有的当前设置来构建代码或实现。 此时您已将“当前设置”编辑为我无法理解的,因此我无法回答。我已经回答了您最初回答的问题;如果您想要两个不同部分的两种不同装饰,按照您最初显示代码的方式,您需要两个不同的kind 字符串。【参考方案2】:

所以此时你已经改变了你的问题。在评论中,您说:

假设我只有一个注册类,对于当前设置的背景视图,有没有办法为一个部分而不是整个布局实现它?

当然,虽然我不知道“使用当前设置”是什么意思,因为你现在拥有的代码(当前设置)显然是错误的,否则你会得到你想要的结果。

无论如何,这很简单:在您的部分提供程序功能中,只给那个部分一个装饰视图,不要给任何其他部分一个装饰视图!

这是一个集合视图的截图,其中只有第一部分有背景装饰视图:

代码很简单:

private func createLayout() -> UICollectionViewLayout 
    let lay = UICollectionViewCompositionalLayout  ix, env in
        // ... create item and group (omitted) ...
        let section = NSCollectionLayoutSection(group: group)
        // ... create header (omitted) ...
        // okay, create decoration!
        let deco = NSCollectionLayoutDecorationItem.background(elementKind: "background")
        deco.contentInsets = NSDirectionalEdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5)
        if ix == 0  // only add the decoration for section 0
            section.decorationItems = [deco]
        
        return section
    
    return lay

【讨论】:

但是看看我的代码。在您的评论中,您正在调用 UICollectionViewCompositionalLayout 初始化程序init(section:)。但如果你这样做,所有部分都将是相同的。你必须做你看到 me 做的事:致电init(sectionProvider:)。这样,您可以为每个部分做一些不同的,就像我在我的代码中所做的那样。当您说 let layout = UICollectionViewCompositionalLayout sectionIndex, layoutEnvironment 时,您确实使用了该初始化程序,因此您有了一个良好的开端。

以上是关于如何为 UICollectionViewCompositionalLayout 中的不同部分设置多个背景视图的主要内容,如果未能解决你的问题,请参考以下文章

如何为下拉菜单制作 CSS 边框?

如何为 CAShapeLayer 路径和填充颜色设置动画

iPhone - 如何为图像着色?

如何为 RecyclerView 设置 onItemClickListener? [复制]

WCF - 如何为 NTLM 身份验证配置 netTcpBinding?

如何为 UIToolbar 上的按钮添加滚动?