본문 바로가기
WWDC

[WWDC] Advances in Collection View Layout

by 차코.. 2025. 2. 4.

https://developer.apple.com/videos/play/wwdc2019/215

 

Advances in Collection View Layout - WWDC19 - Videos - Apple Developer

Collection View Layouts make it easy to build rich interactive collections. Learn how to make dynamic and responsive layouts that range...

developer.apple.com

 


 

Current state-of-the-art


 

CollectionView는 두 가지 클래스로 구성되는데요.

하나는 렌더링, 하나는 항목이 어디에 배치될 지 결정하는 역할을 합니다.

 

이 레이아웃이 추상적인 개념이라, 이를 활용하려면 서브클래싱을 해야 했습니다.

(상속 받아서 확장)

 

 

 

iOS 6부터 UICollectionViewFlowLayout이라는 구체적인 레이아웃 클래스가 제공되기 시작했고,

line-based layout이었기에 정해진 방향으로 아이템을 배치하다가,

가능한 공간이 부족해지면 다음 줄로 넘어가는 형태였습니다.

 

 

하지만 오늘날의 앱은 화면 크기도 다양해지고, 앱의 UI도 점점 복잡해지고 있습니다.

 

 

 

앱 스토어의 화면을 구현하라고 가정했을 때, Flow Layout로 구현할 수 있을까요?

 

대부분 바로 커스텀 레이아웃을 선택할텐데요, 

하지만 커스텀 레이아웃은 너무 복잡합니다.

 

 

 

고려해야 할 것들이 것들이 너무 많아 불편합니다.

 

 


A new approach: Compositional Layout

 

그래서 Compositional Layout이 새롭게 등장했습니다.

 

 

Compositional Layout의 세 가지 특징은 다음과 같습니다.

1. 조합 가능성(Composability) - 단순한 요소들을 조합해 복잡한 레이아웃을 잘 구성하도록
2. 유연성(Flexibility) 
3. 빠른 성능(Performance) - 최적화가 내장되어 있음

 

또한, 선언형 API(Declarative API)를 기반으로 작동되어 있습니다.

 

 


 

 

그런데, 왜 Composing 일까요?

 

 

 

컴포지셔널 레이아웃은

기본적으로 작은 레이아웃 단위들을 결합하여 더 큰 레이아웃을 구성하는 방식입니다.

 

아이템 개수를 아는 것과 상관 없이, 이 항목들이 특정 Layout Group 안에 배치되도록 설계하는 건데요.

 

중요한 건 기존의 번거로운 서브클래싱 없이도 동작한다는 장점이 있다는 것입니다.

 

 


 

 

단순 List 예제

 

단순한 List를 구현하는 예제입니다.

 

 

"이거 Flow Layout에서는 2줄이면 될 텐데, 왜 이렇게 복잡해 보이지?" 

 

물론 Flow Layout이면 더 간단할 수도 있지만,

레이아웃이 복잡해질수록 코드가 점점 많아지는 Flow Layout과 다르게

컴포지셔널 레이아웃에서는 단순 새로운 요소만 추가하면 됩니다.

 

 


 

컴포지셔널 레이아웃에는 다음의 네 가지 타입이 존재합니다.

 

1. 아이템(Item)
2. 그룹(Group)
3. 섹션(Section) - 데이터 소스와 직접 연결
4. 레이아웃(Layout) - CollectionView 전체

 

 

이렇게 아이템 → 그룹 → 섹션 → 레이아웃 구조가 계속 반복되는 형식입니다.

 


 

컴포지셔널 레이아웃의 핵심 개념 중 하나는 Sizing인데요.

 

컴포지셔널 레이아웃은 모든 요소들이 자신의 크기에 대해 strong opinion을 갖고 있습니다.

 

UI는 2D 공간이기에, 모두 width와 height를 가지고 있고 

이 값들은 NSCollectionLayoutDimension이라는 타입을 사용해 정의됩니다.

 

 

 

- 비율(Fractional) - 컨테이너의 크기에 대한 백분율로 지정
- 절대(Absolute) - 픽셀 단위로 정확한 크기를 지정
- 추정(Estimated) - 초기 크기를 추정, 이후 동적으로 조정
- 비율 기반 높이(Fractional Height) - 너비를 기준으로 비율을 유지하면서 크기를 결정

 

 

예를 들어, 아이템이 자신의 컨테이너의 50% 너비를 차지하도록 설정하거나,
높이를 컨테이너의 30%로 설정할 수도 있습니다.

 

 

 

 


 

Item

 


아이템은 화면에 표시되는 하나의 셀 또는 보조 뷰(supplementary view)를 의미합니다.

아이템을 생성할 때는 반드시 크기를 지정해야 합니다.

 

 

 

 


Group

 

그룹은 아이템을 포함하는 역할을 합니다. 

 

 

수평(Horizontal) - 아이템들을 가로로 배치
수직(Vertical) - 아이템들을 세로로 배치
커스텀(Custom) - 직접 좌표를 지정하여 배치

 

커스텀 그룹을 사용하면 사용자 지정 레이아웃(원형이나 비대칭 배치 등)을 구현하는 것이 가능하고,

그룹 안에 그룹을 nesting하는 것 또한 가능합니다.

 


 

 

Section

 

섹션은 데이터 소스에서 제공하는 섹션과 1:1로 매핑됩니다.

 

 

 

 

 


Demos

✅ 예제: List layout

 

 

  1. 아이템을 정의
  2. 아이템을 그룹에 포함 
  3. 그룹을 섹션에 포함
  4. 섹션을 최종 레이아웃으로 설정

 


✅ 예제: Grid Layout

 

위와 동일한 과정인데, 아이템의 너비를 그룹의 20% 로 설정하면, 5개의 열이 됩니다.

높이는 너비와 동일하게 설정했습니다.

 

 


 

✅ 아이템 간 Spacing 추가

 

Insets을 추가해서 아이템 사이에 여백을 줄 수도 있습니다.

 


 

열의 개수가 고정된 경우

 

 


 

 여러 섹션마다 다른 레이아웃을 적용하려면?

 

  • 첫 번째 섹션: 리스트(List)
  • 두 번째 섹션: 5열(Grid)
  • 세 번째 섹션: 3열(Grid)

 

 

SectionLayoutKind 지정할 수 있습니다.

 

이를 활용해, 위와 같이 섹션마다 다른 레이아웃이 그려지도록 지정할 수 있습니다.

 

 

 


 반응형(Adaptive) 레이아웃

 

만약 기기의 너비가 넓어지면 자동으로 더 많은 열을 표시하고자 한다면?

 

layoutEnvironment를 활용하여 현재 화면 크기에 따라 동적으로 레이아웃을 조정할 수 있습니다.

 

 

 

 

예시 코드는 wideMode일 때, 아닐 때 구분지어서 분기해주고 있습니다.

 

 


Advanced layouts

 

CollectionView는 세 가지 기본적인 뷰 타입을 관리하는데요.

 

1. 셀(Cells) - 데이터를 표현하는 기본 요소
2. 보조 뷰(Supplementary Views) - 콘텐츠를 보완하는 뷰 (e.g., 배지, 헤더, 푸터)
3. 데코레이션 뷰(Decoration Views) - 배경 요소 등을 추가할 때 사용

 

 

가장 일반적인 보조 뷰는 배지(Badge), 헤더(Header), 푸터(Footer) 입니다.


Flow Layout에서도 헤더와 푸터를 고정하는 기능을 제공했지만,
컴포지셔널 레이아웃에서는 더 기능이 고도화 되었습니다. 

 

 

 


 

컴포지셔널 레이아웃에서는 Supplementary Views를 특정 아이템이나 그룹에 고정시킬 수 있습니다.

 

 

예를 들어, 아이템의 오른쪽 상단 모서리에 배지를 추가 하고 싶다면,
아래와 같이 NSCollectionLayoutAnchor 를 사용하여 설정할 수 있습니다.

 
 

또 여기에서 fractionalOffset 을 사용하면, 아이템 영역 밖으로 조금 빠져나가도록 설정할 수도 있습니다.

 

 

 

 


✅ Header와 Footer 추가하는 방법

 

 

헤더와 푸터는 일반 보조 뷰와는 약간 다릅니다.
헤더나 푸터가 추가되면, 기존 콘텐츠를 가리지 않고 전체 영역이 확장됩니다.

 

 

 

이를 위해 Boundary Supplementary Item을 사용하는데요. 

 

여기서 .top 을 설정하면, 헤더가 섹션의 맨 위에 고정 됩니다.

 

그리고 pinToVisibleBounds 옵션을 활용하면, 스크롤할 때 헤더가 고정되게 할 수도 있습니다.

 

 


 

✅ 데코레이션 뷰(Decoration View)

 


데코레이션 뷰는 배경 요소를 추가할 때에 사용됩니다.

 

이를 활용해 각 섹션마다 배경을 다르게 지정할 수 있습니다.

 

 

 


✅ 셀 크기를 자동으로 조정 (Self-Sizing) 

 

 

컴포지셔널 레이아웃에서는 각 X, Y축에 대해 개별적으로 크기를 조정할 수 있다고 하는데요.

예를 들어, 헤더의 경우, 너비는 고정된 상태에서 높이만 동적으로 조정 되도록 설정할 수 있습니다.

 
 
 
 
만약에 텍스트 크기를 키울 경우, .estimated(44)를 사용하면 
 
초기 높이를 44pt로 설정한 후, 실제 콘텐츠 크기에 맞게 자동으로 조정됩니다.

 

 

 

 


중첩 그룹(Nested Groups) 

 

 

컴포지셔널 레이아웃에서는 그룹을 중첩해서 복잡한 레이아웃을 구현할 수도 있는데요.

 

 

예를 들어, 위 예시처럼

 

  • 왼쪽에는 큰 아이템 이 있고,
  • 오른쪽에는 세로로 배치된 작은 아이템 그룹

을 구현하고자 한다면,

 

 

 

  1. 작은 아이템 두 개를 포함한 세로 그룹 생성
  2. 세로 그룹과 큰 아이템을 포함하는 가로 그룹 생성

하는 방식으로 중첩된 레이아웃을 쉽게 구현할 수 있습니다.

 

 


 

✅ 콜렉션 뷰 내부에 또 다른 콜렉션 뷰 중첩

 

 

이 기능이 iOS 13의 App Store 디자인을 구현할 때도 사용되었다 하는데요.

 


App Store에는 세로 스크롤 내부에 가로 스크롤 뷰가 포함되어 있습니다.

 

 

 

이전에는 이를 구현하기 위해 각 섹션마다 별도의 CollectionView를 생성해야 했지만,
컴포지셔널 레이아웃에서는 아래와 같이 한 줄만 추가해주면 됩니다.

 
 
 
 
 
가로 스크롤(Orthogonal Scrolling)의 모드에는 여러가지가 있는데요.

 

 

  1. 연속 스크롤(Continuous) - 일반
  2. 그룹 경계 정렬(Continuous Group Leading Boundary) - 그룹 단위로 정렬
  3. 페이지 스크롤(Paging) - 한 페이지씩 이동
  4. 그룹 페이지 스크롤(Group Paging) - 그룹 단위로 페이지 스크롤
  5. 그룹 중앙 정렬 페이지 스크롤(Group Paging Centered) - 그룹이 중앙에 위치