Take a look at the renderings:

UICollectionView does not provide properties or methods to set different background colors for sections. If you want UICollectionView sections to display different background colors, you need to customize a new layout.

Custom layout

1. Customize oneUICollectionViewSectionColorReusableViewInherited fromUICollectionReusableView, as the background view for each group

class UICollectionViewSectionColorReusableView: UICollectionReusableView {

    override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) {
        super.apply(layoutAttributes)
        if let att = layoutAttributes as? UICollectionViewSectionColorLayoutAttributes {
            backgroundColor = att.sectionBgColor
        }
    }
}
Copy the code

2. Customize oneUICollectionViewSectionColorLayoutAttributesinheritanceUICollectionViewLayoutAttributesAnd add one insidesectionBgColorProperty that represents the background color of the section

class UICollectionViewSectionColorLayoutAttributes: UICollectionViewLayoutAttributes {
    var sectionBgColor: UIColor?
}
Copy the code

3. Customize oneUICollectionViewSectionColorFlowLayoutinheritanceUICollectionViewFlowLayoutCalculates and returns the layout properties (location, size, color) for each grouped background view

class UICollectionViewSectionColorFlowLayout: UICollectionViewFlowLayout { var decorationViewAttrs = [UICollectionViewSectionColorLayoutAttributes]() override init() { super.init() register(UICollectionViewSectionColorReusableView.self, forDecorationViewOfKind: "UICollectionViewSectionColorReusableView") } required init? (coder: NSCoder) {fatalError("init(coder:) has not been implemented")} override func prepare() {super.prepare() // number of sections guard let collectionView = collectionView else { return } let numberOfSections = collectionView.numberOfSections guard let delegate = collectionView.delegate as? UICollectionViewSectionColorDelegateFlowLayout else { return } decorationViewAttrs.removeAll() for section in 0.. <numberOfSections { let numberOfItems = collectionView.numberOfItems(inSection: section) guard numberOfItems > 0, let firstItem = layoutAttributesForItem(at: IndexPath(item: 0, section: section)), let lastItem = layoutAttributesForItem(at: IndexPath(item: numberOfItems - 1, section: section)) else { continue } var sectionInset = self.sectionInset if let inset = delegate.collectionView? (collectionView, layout: self, insetForSectionAt: section) { sectionInset = inset } var sectionFrame = firstItem.frame.union(lastItem.frame) sectionFrame.origin.x = 0 sectionFrame.origin.y -= sectionInset.top if scrollDirection == .horizontal { sectionFrame.size.width += sectionInset.left + sectionInset.right sectionFrame.size.height = collectionView.frame.height } else { sectionFrame.size.width = collectionView.frame.width sectionFrame.size.height += sectionInset.top + sectionInset.bottom } / / 2, define the view attributes let attr = UICollectionViewSectionColorLayoutAttributes (forDecorationViewOfKind: "UICollectionViewSectionColorReusableView", with: IndexPath(item: 0, section: section)) attr.frame = sectionFrame attr.zIndex = -1 attr.sectionBgColor = delegate.collectionView?(collectionView, layout: self, backgroundColor: section) decorationViewAttrs.append(attr) } } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { guard let attributes = super.layoutAttributesForElements(in: rect) else { return nil } var allAttributes = [UICollectionViewLayoutAttributes]() allAttributes.append(contentsOf: attributes) for att in decorationViewAttrs { if rect.intersects(att.frame) { allAttributes.append(att) } } return allAttributes } }Copy the code

4, add a protocol method for setting the background color on the outside

@objc protocol UICollectionViewSectionColorDelegateFlowLayout: UICollectionViewDelegateFlowLayout {
    @objc optional func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, backgroundColor section: Int) -> UIColor
}
Copy the code

The above is the whole process of custom layout, summed up in four steps: 1, a custom UICollectionViewSectionColorReusableView inherited from UICollectionReusableView, Used as the background of each group 2, a custom view UICollectionViewLayoutAttributes UICollectionViewSectionColorLayoutAttributes inheritance, Add a sectionBgColor properties, used to represent the background color of the section 3, a custom UICollectionViewFlowLayout UICollectionViewSectionColorFlowLayout inheritance, Calculate and return the layout properties (position, size, color) for each group background view

Now let’s write a demo and see what it looks like

Use case

1. Create oneUICollectionView.collectionViewLayoutuseUICollectionViewSectionColorFlowLayout

private lazy var collectionView: UICollectionView = {
        let layout = UICollectionViewSectionColorFlowLayout()
        layout.itemSize = CGSize(width: (UIScreen.main.bounds.size.width - 51) / 4, height: 65)
        layout.minimumLineSpacing = 10
        layout.minimumInteritemSpacing = 10
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        let collectionView = UICollectionView(frame: UIScreen.main.bounds, collectionViewLayout: layout)
        collectionView.backgroundColor = .gray
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(UICollectionViewCell.self,
                                 forCellWithReuseIdentifier: "UICollectionViewCell")
        collectionView.showsVerticalScrollIndicator = false
        return collectionView
}()
Copy the code

2, comply with theUICollectionViewSectionColorDelegateFlowLayoutProtocol to set background colors for different sections

extension ViewController: UICollectionViewSectionColorDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, backgroundColor section: Int) -> UIColor {
        switch section {
        case 0:
            return .green
        case 2:
            return .blue
        case 3:
            return .cyan
        case 4:
            return .purple
        default:
            return .orange
        }
    }
}
Copy the code

That’s the end of it