관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 1. UICollectionView의 SupplementaryView(HeaderView, FooterView, UICollectionReusableView) 본문

iOS 응용 (swift)

[iOS - swift] 1. UICollectionView의 SupplementaryView(HeaderView, FooterView, UICollectionReusableView)

jake-kim 2022. 3. 8. 23:52

1. UICollectionView의 SupplementaryView(HeaderView, FooterView, UICollectionReusableView)

2. UICollectionView의  DecorationView, SupplementaryView 커스텀 Layout

SupplementaryView 개념

  • SupplementaryView는 UITableView에서의 Header와 Footer와 동일한 개념
  • Section 하나에 위 or 아래에 위치하는 뷰

* 아래부터 예시 코드들은 UI들을 편리하게 작성하기 위해 아래 프레임워크 사용

  pod 'SnapKit'
  pod 'Then'

SupplementaryView에 사용할 커스텀뷰

  • UITableView에서는 HeaderView or FoorterView를 사용할 때 `UITableViewHeaderFooterView` 클래스를 상속하여 뷰를 커스텀하지만, UICollectionView에서는 `UICollectionReusableView`를 커스텀하여 사용

https://developer.apple.com/documentation/uikit/uicollectionreusableview

  • UICollectionReusableView를 상속받은 View 정의
import UIKit
import SnapKit
import Then

final class TitleSupplementaryView: UICollectionReusableView {
  static let id = "TitleSupplementaryView"
  
  private let titleLabel = UILabel().then {
    $0.textColor = .label
    $0.textAlignment = .center
  }
  
  override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = .systemGray4
    self.addSubview(self.titleLabel)
    self.titleLabel.snp.makeConstraints {
      $0.edges.equalToSuperview()
    }
  }
  required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
  override func prepareForReuse() {
    super.prepareForReuse()
    self.prepare(title: nil)
  }
  
  func prepare(title: String?) {
    self.titleLabel.text = title
  }
}

CollectionView에 SupplementaryView 사용 방법

  • UICollectionViewFlowLayout을 사용하는 경우, 사이즈에 대한 입력이 필요 (안해줄 경우 아래에서 볼 dataSource 호출 x)
    • header로 사용하고 싶은 경우: headerReferenceSize 지정 필요 
    • footer로 사용하고 싶은 경우: footerReferenceSize 지정 필요
flowLayout.headerReferenceSize = .init(width: 100, height: 100)
flowLayout.footerReferenceSize = .init(width: 50, height: 50)
  • UICollectionView에 cell을 register(_:forCellWithReuseIdentifier:)로 등록하듯이, SupplementaryView도 등록
    • header로 등록: forSupplementaryViewOfKind파라미터를 .elementKindSectionHeader로 넘기기
    • footer로 등록: forSupplementaryViewOfKind파라미터를 .elementKindSectionFooter로 넘기기
collectionView.register(
  TitleSupplementaryView.self,
  forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
  withReuseIdentifier: TitleSupplementaryView.id
)

collectionView.register(
  TitleSupplementaryView.self,
  forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
  withReuseIdentifier: TitleSupplementaryView.id + "footer"
)

* collectionView 관련 전체 코드

// ViewController.swift

private let collectionView = UICollectionView(
  frame: .zero,
  collectionViewLayout: UICollectionViewFlowLayout().then {
    $0.scrollDirection = .vertical
    $0.minimumLineSpacing = 8.0
    $0.minimumInteritemSpacing = 8.0
    $0.itemSize = CGSize(width: 50, height: 50)
    
    $0.headerReferenceSize = .init(width: 100, height: 100)
    $0.footerReferenceSize = .init(width: 50, height: 50)
  }
).then {
  $0.showsVerticalScrollIndicator = false
  $0.register(ColorCell.self, forCellWithReuseIdentifier: ColorCell.id)
  $0.register(TitleCell.self, forCellWithReuseIdentifier: TitleCell.id)
  $0.register(
    TitleSupplementaryView.self,
    forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
    withReuseIdentifier: TitleSupplementaryView.id
  )
  $0.register(
    TitleSupplementaryView.self,
    forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
    withReuseIdentifier: TitleSupplementaryView.id + "footer"
  )
}
  • dataSource에서 collectionView(_:viewForSupplementaryElementOfKind:at:) 정의
    • kind값은 문자열이고, header인지 footer인지 구분하기 위한 값
    • heaer인 경우 - UICollectionView.elementKindSectionHeader
    • footer인 경우 - UICollectionView.elementKindSectionHeader

* dataSource 코드

extension ViewController: UICollectionViewDataSource {
  func collectionView(
    _ collectionView: UICollectionView,
    viewForSupplementaryElementOfKind kind: String,
    at indexPath: IndexPath
  ) -> UICollectionReusableView {
    switch kind {
    case UICollectionView.elementKindSectionHeader:
      let supplementaryView = collectionView.dequeueReusableSupplementaryView(
        ofKind: kind,
        withReuseIdentifier: TitleSupplementaryView.id,
        for: indexPath
      ) as! TitleSupplementaryView
      supplementaryView.prepare(title: "supplementaryView(header)")
      return supplementaryView
    case UICollectionView.elementKindSectionFooter:
      let supplementaryView = collectionView.dequeueReusableSupplementaryView(
        ofKind: kind,
        withReuseIdentifier: TitleSupplementaryView.id + "footer",
        for: indexPath
      ) as! TitleSupplementaryView
      supplementaryView.prepare(title: "supplementaryView(footer)")
      return supplementaryView
    default:
      return UICollectionReusableView()
    }
  }
}

* 전체 코드: https://github.com/JK0369/ExMultiSectionCollectionView

* 참고

https://developer.apple.com/documentation/uikit/uicollectionreusableview

https://developer.apple.com/documentation/uikit/uicollectionview

 

Comments