How to change background color of a whole section in UICollectionView?
Asked Answered
N

10

48

In UICollectionView, I want to give the whole section a uniform background color, instead of for a single cell or for the whole collection view.

I don't see any delegate method to do that, any suggestions?

Nova answered 28/11, 2012 at 15:58 Comment(1)
try this github.com/devxoul/UICollectionViewFlexLayoutBellybutton
T
15

First, make a UICollectionReusableView to be your background view. I've simply set mine to be red.

class SectionBackgroundDecorationView: UICollectionReusableView {
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = .red
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

Then, in YourCollectionViewController:

static let background = "background-element-kind"

init() {
    super.init(collectionViewLayout: YourCollectionViewController.createLayout())
}

static func createLayout() -> UICollectionViewLayout {
    let layout = UICollectionViewCompositionalLayout { (sectionIndex: Int,
        layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in
        
        // Use sectionIndex to control the layout in each section
        if sectionIndex == 0 {
            
            // Customise itemSize, item, groupSize, group to be whatever you want
            let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                                  heightDimension: .fractionalHeight(1))
            let item = NSCollectionLayoutItem(layoutSize: itemSize)
       
            let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                                   heightDimension: .absolute(170))
            let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

            let section = NSCollectionLayoutSection(group: group)
            
            // Create a sectionBackground
            let sectionBackground = NSCollectionLayoutDecorationItem.background(
                    elementKind: background)

            section.decorationItems = [sectionBackground]
            return section
            
        } else {
            
          // Your layout for other sections, etc
          // You don't have to set a background for other sections if you don't want to
        }
    }
    layout.register(SectionBackgroundDecorationView.self, forDecorationViewOfKind: background)
    return layout
}

These links to documentation helped me:

Toadfish answered 8/10, 2021 at 17:31 Comment(1)
Is there a way to give different background colours to different sections based on the sectionData ?Levania
V
13

The new UICollectionViewCompositionalLayout introduced in iOS 13 have a property named decorationItems for adding decoration items conveniently, which you could use to add a background for the section.

let section = NSCollectionLayoutSection(group: group)
section.decorationItems = [
   NSCollectionLayoutDecorationItem.background(elementKind:"your identifier")
]
Vollmer answered 5/5, 2020 at 8:37 Comment(1)
What is group and how do you obtain it for a given section. This doesn't explain how you use it at all.Archery
H
4

The idea is to override UICollectionViewLayoutAttributes to add a color attribute. And then override UICollectionReusableView apply the color to the view background.

https://github.com/strawberrycode/SCSectionBackground

Hum answered 19/9, 2016 at 18:10 Comment(3)
When i make this example to support all orientation, while moving from portratoit to landscappre or vice versa the app crashes with below error,Pentahedron
SCSectionBackground[34266:300939] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'layout attributes for supplementary item at index path ( {length = 2, path = 0 - 0}) changed from <SCSectionBackground.SCSBCollectionViewLayoutAttributes: index path: (< {length = 2, path = 0 - 0}); element kind: (sectionBackground); frame = (0 0; 667 116); zIndex = -1; to <SCSectionBackground.SCSBCollectionViewLayoutAttributes:> index path: ( {length = 2, path = 0 - 0}); element kind: (sectionBackground); frame = (0 0; 375 116); zIndex = -1;Pentahedron
without invalidating the layout'. Could you help to resolve this ?Pentahedron
S
2

I haven't tried this out yet, but it looks to me that you need to use decoration views if you want a background behind your cells (like the shelf in the Books app). I think you should be able to have different views for each section, and set them up using the delegate method layoutAttributesForDecorationViewOfKind:atIndexPath:.

Shan answered 28/11, 2012 at 17:34 Comment(0)
P
2

refer to:
strawberrycode: Use DecorationView as background
devxoul: Use SupplementaryElement as background
airbnb: Use SupplementaryElement as background

I need to compatible with IGListKit, so I use decorationView as background. The layout is subclass from UICollectionViewFlowLayout for common use case. My implementation: different section background

Pandarus answered 17/9, 2019 at 4:31 Comment(0)
F
0

In collection view every section can have a supplementary views, so put supplementary views for each section then set background color to supplementary views instead of section cells. I hope it will help.

Fluorite answered 3/12, 2013 at 14:6 Comment(3)
When reading about supplementary views, I only find examples when it is used for headers & footers. Do you have any example and/or working code for your answer.Lamplighter
I have done it by using collection view custom layout. In custom layout my supplementary view frame is equal to that entire section frame.Fluorite
How did you manage to do that? if you could tell that would be great. ThanksEdla
T
0

One of the classic approach is to create a Custom Supplementary Kind and provide your custom view in CollectionView Section background. It will give you the ability to customize section backgrounds. Refer to https://mcmap.net/q/371946/-how-to-add-a-background-image-to-uicollectionview-that-will-scroll-and-zoom-will-cells

Tammany answered 26/8, 2020 at 13:13 Comment(0)
S
-1

I went off of this repo here https://github.com/SebastienMichoy/CollectionViewsDemo/tree/master/CollectionViewsDemo/Sources/Collections%20Views

Swift 3

subclass uicollectionreusableview

class SectionView: UICollectionReusableView {
   static let kind = "sectionView"
}

subclass uicollectionViewFlowLayout

class CustomFlowLayout: UICollectionViewFlowLayout {

// MARK: Properties

var decorationAttributes: [IndexPath: UICollectionViewLayoutAttributes]
var sectionsWidthOrHeight: [IndexPath: CGFloat]


// MARK: Initialization

override init() {
    self.decorationAttributes = [:]
    self.sectionsWidthOrHeight = [:]

    super.init()
}

required init?(coder aDecoder: NSCoder) {
    self.decorationAttributes = [:]
    self.sectionsWidthOrHeight = [:]

    super.init(coder: aDecoder)
}

// MARK: Providing Layout Attributes

override func layoutAttributesForDecorationView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return self.decorationAttributes[indexPath]
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var attributes = super.layoutAttributesForElements(in: rect)
    let numberOfSections = self.collectionView!.numberOfSections
    var xOrYOffset = 0 as CGFloat

    for sectionNumber in 0 ..< numberOfSections {
        let indexPath = IndexPath(row: 0, section: sectionNumber)
        let numberOfItems = self.collectionView?.numberOfItems(inSection: sectionNumber)
        let sectionWidthOrHeight = numberOfItems == 0 ? UIScreen.main.bounds.height : collectionViewContentSize.height//self.sectionsWidthOrHeight[indexPath]!
        let decorationAttribute = UICollectionViewLayoutAttributes(forDecorationViewOfKind: SectionView.kind, with: indexPath)
        decorationAttribute.zIndex = -1

        if self.scrollDirection == .vertical {
            decorationAttribute.frame = CGRect(x: 0, y: xOrYOffset, width: self.collectionViewContentSize.width, height: sectionWidthOrHeight)
        } else {
            decorationAttribute.frame = CGRect(x: xOrYOffset, y: 0, width: sectionWidthOrHeight, height: self.collectionViewContentSize.height)
        }

        xOrYOffset += sectionWidthOrHeight

        attributes?.append(decorationAttribute)
        self.decorationAttributes[indexPath] = decorationAttribute
    }

    return attributes
}
}

implement this

CollectionView delegate function

func collectionView(_ collectionView: UICollectionView, willDisplaySupplementaryView view: UICollectionReusableView, forElementKind elementKind: String, at indexPath: IndexPath) {

    Log.printLog(identifier: elementKind, message: indexPath)
    if elementKind == UICollectionElementKindSectionHeader, let view = view as? ProfileViewHeaderView {

        view.backgroundColor = UIColor(red: (102 / 255.0), green: (169 / 255.0), blue: (251 / 255.0), alpha: 1)
    } else if elementKind == SectionView.kind {
        let evenSectionColor = UIColor.black
        let oddSectionColor = UIColor.red

        view.backgroundColor = (indexPath.section % 2 == 0) ? evenSectionColor : oddSectionColor
    }
}

This is important

let layout = CustomFlowLayout()
layout.register(SectionView.self, forDecorationViewOfKind: SectionView.kind)

register the UICollectionReusableView with layout not collectionView.

one more thing. I messed around with the height in layoutAttributesForElements. you should change it for your own project.

Sandhi answered 8/8, 2017 at 15:38 Comment(0)
W
-1

Its very simple just use this default UICollectionViewDelegate's method, it will works

func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
    print(indexPath.item)

    let evenSectionColor = UIColor.clear
    let oddSectionColor = UIColor.white
    cell.contentView.backgroundColor = (indexPath.item % 2 == 0) ? evenSectionColor : oddSectionColor

}
Wace answered 6/8, 2019 at 22:20 Comment(0)
M
-4

I have changed the background color of each section in a very simple manner in the following method: But I was not sure whether it is the right thing to do. But it did work.

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    FamilyCalendarCellItemCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"calendarItem" forIndexPath:indexPath];
    Event *event;
    _headerView = [collectionView dequeueReusableSupplementaryViewOfKind:
                   UICollectionElementKindSectionHeader withReuseIdentifier:@"EventHeader" forIndexPath:indexPath]; //headerView is declared as property of Collection Reusable View class
    if(indexPath.section==0) {

        cell.backgroundColor=[UIColor orangeColor];
        }
    else if(indexPath.section==1) {

        cell.backgroundColor=[UIColor yellowColor];

    }

    return cell;
}
Modla answered 29/2, 2016 at 4:58 Comment(1)
This only changes the background colour of the cells. The question is asking for how to change the background colour of the collection view itself within a given sectionBelindabelisarius

© 2022 - 2024 — McMap. All rights reserved.