iOS/UIKit

[UIKit] : CollectionView Header 만들기 - (UICollectionReusableView)

SeorinY 2022. 9. 2. 16:49

Collection View에서 UICollectionReusableView를 사용하여 header를 만들어보자.

전 글에서 CollectionView 를 만들었으니 코드를 이어서 작성해보자!

참고  :  https://seorin-yy.tistory.com/19

 

[Swift] : CollectionView 생성, Cell 등록하기

정말 많이 사용되는 CollectionView 를 띄워보자. Collection View 를 생성하기 전에 먼저 CollectionView 에서 사용될 Cell 을 만들어보자 UICollectionViewCell를 상속받는 Cell을  생성해주자. 그리고 알 수..

seorin-yy.tistory.com

UICollectionReusableView를 사용하여 Header를 만들게 되면 각 Section마다 Header가 생성될 것이다.

 

 

먼저 UICollectionReusableView를 사용해서 header 뷰를 만들어보자!

class HeaderCollectionReusableView: UICollectionReusableView {
    static let identifier = "HeaderCollectionReusableView"
    //Header를 알려줄 label
    private let label : UILabel = {
        let label = UILabel()
        label.text = "Header"
        return label
    }()
    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(label)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = CGRect(x: 20, y: 0, width: 100, height: 30)
    }
}

 

이제 HeaderCollectionReusableView를 사용할 ViewController에서 HeaderCollectionReusableView를 등록해주자.

viewDidLoad에 아래 코드를 추가해주자

collectionView?.register(HeaderCollectionReusableView.self, 
			forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, 
		        withReuseIdentifier: HeaderCollectionReusableView.identifier)

그리고 UICollectionViewDelegateFlowLayout 를 사용하여 header를 띄워주고  크기를 정해주자!

아래 함수를 정의해주면 된다

    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        guard kind == UICollectionView.elementKindSectionHeader else{
            return UICollectionReusableView()
        }
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HeaderCollectionReusableView.identifier, for: indexPath) as! HeaderCollectionReusableView
        return headerView
    }
    
    
    //layout 을 쳐서 referenceSizeForHeaderInsection 을 사용해서 Reusable View 의 크기를 정해주자   - 바로 리턴하면 됨
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: 300, height: 50)
    }

 

 

이제 실행하면 위 결과처럼 잘 나올 것이다.

 

 

전체코드

import UIKit


class ViewController: UIViewController{
    //collectionView를 생성해주자
    private var collectionView : UICollectionView?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        configureCollectionView()
    }
    
    private func configureCollectionView(){
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.itemSize = CGSize(width: 50 , height:50)
        layout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
        //위 layout들로 UICollectionView를 생성해주자
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView?.backgroundColor = .systemBackground
        //collectionView에서 사용하고 싶은 cell을 identifier를 사용하여 등록해주자!!
        collectionView?.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.identifier)
        //collectionView에서 사용하고 싶은 Header를 identifier를 사용하여 등록해주자!!
        collectionView?.register(HeaderCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: HeaderCollectionReusableView.identifier)
        
        collectionView?.delegate = self
        collectionView?.dataSource = self
        guard let collectionView = collectionView else {
            return
        }
        view.addSubview(collectionView)
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView?.frame = view.bounds
    }
}
extension ViewController : UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        5
    }
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.identifier, for: indexPath) as? CollectionViewCell else { return UICollectionViewCell() }
        return cell
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 3
    }
    
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        guard kind == UICollectionView.elementKindSectionHeader else{
            return UICollectionReusableView()
        }
        let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HeaderCollectionReusableView.identifier, for: indexPath) as! HeaderCollectionReusableView
        return headerView
    }
    
    
    //layout 을 쳐서 referenceSizeForHeaderInsection 을 사용해서 Reusable View 의 크기를 정해주자   - 바로 리턴하면 됨
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
        return CGSize(width: 300, height: 50)
    }
}


class CollectionViewCell: UICollectionViewCell {
    static let identifier = "CollectionViewCell"
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        //Cell에서는 View대신 ContentView를 사용한다
        contentView.backgroundColor = .blue
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

class HeaderCollectionReusableView: UICollectionReusableView {
    static let identifier = "HeaderCollectionReusableView"
    //Header를 알려줄 label
    private let label : UILabel = {
        let label = UILabel()
        label.text = "Header"
        return label
    }()
    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(label)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        label.frame = CGRect(x: 20, y: 0, width: 100, height: 30)
    }
}