본문 바로가기

iOS/STUDY

[iOS] Compositional Layout 에 관하여

CollectionView를 무작정? 쓰다가 레이아웃 잡을 때 감으로 때려 맞추는 일을 그만하기 위해서 정리를 해보려고 합니다..

 

Layout

우선 레이아웃을 사용하는 이유는 컬렉션 뷰의 컨텐츠를 정렬하기 위해서입니다.

레이아웃이 잘 잡혀있으면 컨텐츠를 그냥 넣기만 하면 레이아웃대로 구성이 되기 때문이죠!

 

이 레이아웃을 커스텀 하는 방법으로는 두 가지 방법이 있습니다.

UICollectionViewFlowLayout

UICollectionViewCompositionalLayout

 

우선 flow 레이아웃은 iOS 6.0+ , compositional 레이아웃은 iOS 13.0 + 에서 사용 가능합니다.

flow 레이아웃이 훨씬 오래됐다는 것을 알 수 있죠

 

두 레이아웃 객체 모두 UICollectionViewLayout 을 상속받습니다. 이름부터 딱 컬렉션 뷰의 레이아웃이다를 알려주고 있네요.


UICollectionViewFlowLayout

A layout object that organizes items into a grid with optional header and footer views for each section.

각 Section에 대해 헤더와 푸터가 있을 수 있고 item을 그리드로 구성하는 레이아웃 객체입니다.

 

Flow 레이아웃은 UICollectionViewDelegateFlowLayout 프로토콜을 채택하면 레이아웃을 동적으로 조절할 수 있습니다.

(예를 들어 item의 사이즈를 다양한 크기로 지정할 수 있습니다. 지정하지 않으면 기본값을 사용합니다!)

 

문서 내용은 아니지만 셀의 크기를 조정하는 방법 두 가지가 더 있다고 합니다.

UICollectionViewFlowLayout 클래스의 itemSize프로퍼티를 이용해 모든 셀을 같은 크기로 설정하는 방법과

셀에 오토 레이아웃을 적용하고 셀 스스로 크기를 결정한 후 이를 UICollectionViewLayout 객체에 알려주는 방법. 이 방법을 사용하려면 estimatedItemSize 프로퍼티를 사용해 대략적인 셀의 최소 크기를 미리 알려줘야 한다고 합니다.

 

Flow 레이아웃의 기본 스크롤 방향을 세로지만 가로로도 구성할 수 있고,

스크롤 방향의 높이 (or 가로) 는 그리드의 section 및 item 수와 일치되도록 동적으로 조정됩니다.

 

Flow 레이아웃은 Section 안에 item 을 그리드 방식으로 구현한다는 것을 알 수 있었습니다.!

Flow 레이아웃은 이론적인 부분만 알고 Compositional 레이아웃을 알아보겠습니다.

 


Compositional Layout 이 나온 이유?

이 Flow 레이아웃에서 애플이 Compositional Layout을 새롭게 낸 이유는 무엇일까요..?

Flow 레이아웃은 복잡한 레이아웃을 구축하는데 한계가 있다고 합니다.

앱스토어만 보더라도 여러 Section 에 모두 다른 구성으로 이루어져 있다는 사실을 알 수 있는데 이를 Flow 레이아웃으로 구현하려면 어렵다고 합니다만.. 사실 Flow 레이아웃을 많이 안 써봐서 확 와닿지는 않네요..ㅎㅎ

 

아무튼 Compositional Layout을 사용하면 커스텀할 subClass를 생성할 필요 없이 선언적인 접근 방식으로 레이아웃을 단순하게 구성할 수 있다고 합니다.

 

 


 

UICollectionViewCompositionalLayout

A layout object that lets you combine items in highly adaptive and flexible visual arrangements.

높은 적응력과 유연한 시각적인 배열로 item을 결합할 수 있는 레이아웃 객체입니다. (높은 적응력..?)

(아무튼 유연하고 빠르게 설계되었다)

 

Compositional 레이아웃을 구성하는 방법으로 Flow 레이아웃의 Section 과 item 사이에 Group 의 개념을 도입하여 

Section, Group, item 으로 구성할 수 있습니다.

 

Group 과 Section, item 에는 차이점이 있습니다.

Section 과 item 은 컬렉션 뷰 데이터 소스의 Section, item 과 1:1 로 대응되지만,

Group은 해당하는 데이터 소스가 없습니다.

-> 이 말은  Gruop은 Section 내에서 item의 레이아웃만을 위해 만들어진 개념이라고 볼 수 있습니다.

 


Compositional Layout 을 코드로 작성해보자

func createBasicListLayout() -> UICollectionViewLayout { 
    let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                  
                                         heightDimension: .fractionalHeight(1.0))    
    let item = NSCollectionLayoutItem(layoutSize: itemSize)  
  
    let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),                                          
                                          heightDimension: .absolute(44))    
    let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize,                                                   
                                                     subitems: [item])  
  
    let section = NSCollectionLayoutSection(group: group)    

    let layout = UICollectionViewCompositionalLayout(section: section)    
    return layout
}

 

문서에 적혀 있는 가장 기본적인 리스트 레이아웃입니다~

사실 이 코드 때문에 글을 작성하게 됐습니다.

 

레이아웃을 만드는 단계를 변수명으로만 알아보자면~

 

1. item 사이즈로 item 레이아웃을 만들고,

2. group 사이즈와 group 안에 들어갈 item으로 group을 만듭니다.

3. 그리고 이 group을 section으로 구성해서 CompositionalLayout을 생성하면 끝!!

 

 

 

그럼 우선 사이즈를 만드는 방법을 알아봅시다.

사이즈는 NSCollectionLayoutSize 라는 객체를 사용해서 만듭니다.

NSCollectionLayoutSize

컬렉션 뷰 item의 width와 height를 나타내는 객체입니다. (item의 범주에는 group도 포함되나 봅니다.)

그리고 생성할 때는 NSCollectionLayoutDimension 타입의 값을 넣어줍니다. (widthDimension, heightDimension)

NSCollectionLayoutDimension 타입의 값을 넣어주는 방법은 세 가지가 있습니다.

 

1. absolute(CGFloat)

절댓값을 사용하여 44 x 44 정사각형 사이즈를 지정하는 예시입니다.

let absoluteSize = NSCollectionLayoutSize(widthDimension: .absolute(44),
                                         heightDimension: .absolute(44))

 

2. estimated(CGFloat)

데이터가 로드되거나 글꼴 크기가 변경된 경우 같이 런타임에 콘텐츠 크기가 변경될 수 있는 경우에는

예상 값을 사용합니다. 예상 크기를 제공하면 시스템이 실제 값을 계산하여 사용하게 됩니다.

let estimatedSize = NSCollectionLayoutSize(widthDimension: .estimated(200),
                                          heightDimension: .estimated(100))

 

3. fractionalWidth(CGFloat), fractionalHeight(CGFloat)

item 의 상대적인 값을 정의할 때는 fractional 값을 사용합니다.

예를 들어 이 코드에서는 item 너비가 20% 의 크기를 가지며 컨테이너의 크기가 변경됨에 따라서 커지고 축소될 수 있습니다.

let fractionalSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.2),
                                           heightDimension: .fractionalWidth(0.2))

 

 

이렇게 레이아웃 사이즈 객체를 만들고 나면 NSCollectionLayoutItem, NSCollectionLayoutGroup 을 만들 수 있습니다.

NSCollectionLayoutItem

컬렉션 뷰의 가장 기본적인 구성 요소입니다.

이 객체는 앞서 만든 레이아웃 사이즈 객체로 생성할 수 있습니다.

그리고 edgeSpacing, contentInsets 로 간격을 조정할 수 있습니다!

 

NSCollectionLayoutGroup

경로 (스크롤등,,) 에 따라 item을 배치하는 컨테이너입니다.

생성 시 horizontal, vertical 을 설정할 수 있으며 custom 도 가능합니다. (어떻게 custom 하는지는 나중에..?)

그리고 subitems에 만들었던 NSCollectionLayoutItem 타입의 item을 넣어줍니다.

group에서도 interItemSpacing 값을 통해 item 간격을 조정할 수 있습니다.

 

NSCollectionLayoutSection

group 들을 이제 결합하는 컨테이너입니다.

앞서 만든 Group으로 Section을 만들어주면  이제 CompositionalLayout을 생성할 수 있습니다.

 

 

UICollectionViewCompositionalLayout

let layout = UICollectionViewCompositionalLayout(section: section)

 

 

 

Flow layout 과의 가장 큰 차이점은 group이 포함되었다는 점인 것 같습니다. ㅎ.ㅎ 그리고 레이아웃 구성 방법!!

어떤 게 더 좋다고 정답은 없지만 코드를 보고 이해하기 쉬운 것은 Compositional Layout이라고 생각합니다.

 

 

 

+ 번외로 CompositionalLayout 에서 list 를 생성할 수도 있습니다. (iOS 14.0+)

개인적인 사용 경험으로는 기본적인 List 를 구성하는 데는 매우 편리하지만

커스텀의 영역으로 넘어가면 구성하기 어렵다는 느낌을 많이 받았습니다 ㅠ.ㅠ

더 많은 리스트 구현이 있으면 좋겠다는 개인적인 바람입니다 ㅎ.ㅎ

 

 

아래 코드를 다운로드하면 다양한 Compositional Layout 예시를 확인해 볼 수 있습니다.  ( + Diffable DataSource ) 

https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/implementing_modern_collection_views

 

Apple Developer Documentation

 

developer.apple.com

 

 

 

 

 

https://developer.apple.com/documentation/uikit/views_and_controls/collection_views/layouts

 

Apple Developer Documentation

 

developer.apple.com

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

 

Apple Developer Documentation

 

developer.apple.com

https://k-elon.tistory.com/26

 

[iOS] UICollectionView 톺아보기 - 3

이전 시간에 UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate에 대해서 알아보았구 이번 포스팅에서는 컬렉션뷰의 셀을 원하는 형태로 정렬하고 간격을 지정하는 등의 기능을 하는 U..

k-elon.tistory.com

https://lickability.com/blog/getting-started-with-uicollectionviewcompositionallayout/

 

Getting Started with UICollectionViewCompositionalLayout

At WWDC 2019, Apple introduced and later documented an unbelievable API for building complex layouts with ease. UICollectionViewCompositionalLayout promised to simplify collection view layouts using a more declarative approach without the need to subclass

lickability.com

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

 

Apple Developer Documentation

 

developer.apple.com

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

 

Apple Developer Documentation

 

developer.apple.com