UICollectionViewCompositionalLayout : Background Decoration View 로 section에 백그라운드 입히는 방법

Doyeong Kim·2023년 8월 2일
3

Swift

목록 보기
3/9

CollectionView Compositional Layout 으로 셀 구성 중에 section에 배경 색을 어떻게 넣는지 찾아보니 Decoration View 를 사용하면 되더라구요!

저는 3번째 섹션에 그레이 색상의 백그라운드 뷰를 넣었어요!

  1. 먼저 백그라운드 뷰로 사용할 UICollectionReusableView 를 생성해줍니다.
class GrayBackgroundView: UICollectionReusableView {
    private let grayBackgroundView = UIView().then {
        $0.backgroundColor = .lightGray //UIColor(red: 246, green: 247, blue: 251)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .clear
        addSubview(grayBackgroundView)

        grayBackgroundView.snp.makeConstraints {
            $0.top.leading.trailing.bottom.equalToSuperview()
        }
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
  1. header는 boundarySupplementaryItems에, background는 decorationItems에 각각 지정해줍니다.
	private func pickLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(300), heightDimension: .estimated(313))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = 16
        section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 16, trailing: 16)
        section.supplementariesFollowContentInsets = false

        let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(56))
        let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize,
                                                                        elementKind: UICollectionView.elementKindSectionHeader,
                                                                        alignment: .topLeading)
        section.boundarySupplementaryItems = [headerElement]
        section.orthogonalScrollingBehavior = .groupPaging

        // Background
        let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background(elementKind: "macapickBackground")
        section.decorationItems = [sectionBackgroundDecoration]
        
        return section
    }
  1. 여기서 주의해야할 점은!

    Supplementary Header View는 UICollectionView 내에서 register()
    Decoration View는 UICollectionViewCompositionalLayout 내에서 register() 해야합니다.

저는 예제 코드를 보면서 하는데 계속 register가 안됐다면서 fatal error가 뜨는 거에요.. 어떻게 어떻게 하다가 찾은 방법은 아래입니다!

	private func createLayout() -> UICollectionViewLayout {
        let layout = UICollectionViewCompositionalLayout { [weak self] (sectionIndex, environment) -> NSCollectionLayoutSection? in
            switch sectionIndex {
            case 0: return self?.bannerLayout()
            case 1: return self?.categoryLayout()
            case 2: return self?.pickLayout()
            default: return nil
            }
        }
        
        // Register decoration view
        layout.register(GrayBackgroundView.self,
                        forDecorationViewOfKind: "macapickBackground")
        
        return layout
    }
  1. 마지막으로 컬렉션뷰의 collectionViewLayout에 위에서 작성한 createLayout() 함수를 넣어주면 끝~
	private lazy var collectionView = UICollectionView(frame: .zero, collectionViewLayout: createLayout()).then {
        $0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "bannerCell")
        $0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "categoryCell")
        $0.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "macapickCell")
        $0.register(UICollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "macapickHeader")
        $0.backgroundColor = .clear
        $0.dataSource = self
    }

아 아까 decoration view가 계속 register가 안된다고 오류가 나던 코드는 이 문제였어요..

	private func pickLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .absolute(300), heightDimension: .estimated(313))
        let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.interGroupSpacing = 16
        section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 16, bottom: 16, trailing: 16)
        section.supplementariesFollowContentInsets = false
        section.orthogonalScrollingBehavior = .groupPaging

        let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(56))
        let headerElement = NSCollectionLayoutBoundarySupplementaryItem(layoutSize: headerSize,
                                                                        elementKind: UICollectionView.elementKindSectionHeader,
                                                                        alignment: .topLeading)
        section.boundarySupplementaryItems = [headerElement]

        // Background
        let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background(elementKind: "macapickBackground")
        section.decorationItems = [sectionBackgroundDecoration]
        
        // section을 리턴하는 함수 안에서 layout 인스턴스를 새로 생성해 register()를 해줬더니 안되는 거였음..ㅠㅠ
        let layout = UICollectionViewCompositionalLayout(section: section)
        layout.register(GrayBackgroundView.self, forDecorationViewOfKind: "macapickBackground")
        
        return section
    }
profile
신비로운 iOS 세계로 당신을 초대합니다.

2개의 댓글

comment-user-thumbnail
2023년 8월 2일

글 잘 봤습니다.

답글 달기
comment-user-thumbnail
2023년 12월 5일

업무에 많은 도움되었습니다!

답글 달기