[iOS] UICollectionViewCompositionalLayout 만들기

eung7_·2022년 5월 9일
1

iOS

목록 보기
13/17
post-thumbnail

UICollectionViewCompositionalLayout

  • 기존의 UICollectionViewLayout보다 더 확장된 레이아웃 제공
  • 그림처럼 여러 섹션으로 나누어서 각 섹션끼리 관리 가능
  • item, group, section 순으로 적용해나가면 된다.

기존 UICollectionViewLayout으로는 구현하기 힘든 여러 가지 UI들을 적용가능
각 섹션마다 서로 다른 레이아웃을 가지는 데도 쉽게 관리할 수 있음
기존 Layout은 하나의 콜렉션 뷰로 다양한 레이아웃을 가진 ScrollView를 갖기 쉽지 않음

예를 들어 요즘 앱들에서 많이 보이는 이런 디자인들..


CompositionalLayout 만들기

CompositionalSection 정의

func createBasicLayout() -> NSCollectionLayoutSection {
    /// 각 item의 사이즈 설정 ( width: 120, height: 160 )
    let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(120.0), heightDimension: .absolute(160.0))
    let item = NSCollectionLayoutItem(layoutSize: itemSize)
    /// 아이템의 마진 값 설정
    item.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)

    /// 아이템들이 들어갈 Group 설정
    /// groupSize 설정
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.9), heightDimension: .absolute(160.0))
    /// subitem에 item을 넣어주고 각 그룹 당 아이템이 보여질 갯수는 3개
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitem: item, count: 3)

    /// 최종적으로 section 설정
    let section = NSCollectionLayoutSection(group: group)

    /// 헤더 생성
    let titleHeader = createTitleHeaderLayout()
    /// 이 Layout은 헤더를 보여지도록 적용
    section.boundarySupplementaryItems = [ titleHeader ]
    /// 어떤 형식의 스크롤을 쓸지 결정
    section.orthogonalScrollingBehavior = .continuous

    return section
}

먼저 NSCollectionLayoutSection을 만들어주는 메서드 구현
위에서 말했 듯이 Item, Group, Section 순으로 만들어주고 차례차례 인자로 넣어주는 것이 보임

UICollectionViewCompositionalLayout 반환

func createLayout() -> UICollectionViewCompositionalLayout {
    /// return 값인 UICollectionViewCompositionalLayout은 콜백 함수로 두 개의 인자가 나온다.
    ///
    /// 콜백 함수 :
    /// sectionNumber [int] : sectionNumber마다 다르게 줄 수 있도록하는 인자
    /// env [NSCollectionLayoutEnvironment] : 사이즈, 인셋 등을 줄 수 있는 인자
    /// return [NSCollectionLayoutSection] : 만들어두었던 NSCollectionLayoutSection 객체를 넣어주면 최종적으로 Layout으로 반환됨
    return UICollectionViewCompositionalLayout {[weak self] sectionNumber, env -> NSCollectionLayoutSection? in
        /// section 번호마다 다른 Layout을 설정하기 위해 switch 문
        switch sectionNumber {
        case 0:
            return self?.createMainLayout()
        default:
            return self?.createBasicLayout()
        }
    }
}

최종 적으로 UICollectionView에 넣을 수 있는 Layout객체로 반환해주는 메서드 구현
굳이 Section과 Layout을 반환하는 메서드를 나눈 이유는
반환 값인 UICollectionViewCompositionalLayout의 콜백함수의 리턴 타입을 보면 알 수 있다.
코드를 보면 sectionNumber로 switch구문을 작성한 것이 눈에 띰

반환값인 UICollectionViewCompositionalLayout은 콜백함수로 섹션 번호랑, 레이아웃의 환경을 설정할 수 있는 인자를 반환받음
여기서 모든 레이아웃을 한꺼번에 만들 수 있지만, 그러면 한 메서드 안에 코드가 너무 복잡해져 필자는 따로 나누는 것을 추천

왜 UICollectionViewCompositionalLayout이라는 값은 콜백함수로 이런 값을 가지는가?
생각해보면 섹션 마다 각 커스텀한 레이아웃을 갖고 있을 것이기 때문에 이렇게 되어있는 것이 어찌보면 당연하다.

CollectionView의 Layout으로 추가

lazy var collectionView: UICollectionView = {
    let layout = createLayout()
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
    collectionView.register(MovieCollectionViewCell.self, forCellWithReuseIdentifier: MovieCollectionViewCell.identifier)
    collectionView.register(MovieMainCollectionViewCell.self, forCellWithReuseIdentifier: MovieMainCollectionViewCell.identifier)
    collectionView.register(MovieCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: MovieCollectionHeaderView.identifier)
    collectionView.dataSource = self

    return collectionView
}()

최종적으로 collectionView를 초기화 할 떄
createLayout() 메서드를 반환 받아서 섹션 마다 다른 레이아웃을 갖고 있는 레이아웃 객체를 생성
이제 섹션 마다 서로 다른 레이아웃을 갖고 있는 collectionView를 가질 수 있게 된다.


고찰

일반적으로 각 섹션마다 동일한 레이아웃을 사용할 거면 그냥 사용했던 UICollectionViewLayout을 사용하면 편할 것이라고 생각한다.
그런데 요즘 앱 트렌드 상 재밌는 UI들이 많이 출시하기 때문에 알아둬야 한다고 생각한다.

profile
안녕하세요. SW Engineer eung7입니다.

0개의 댓글