suvera-dev 🥦

iOS) Compositional Layout 본문

iOS

iOS) Compositional Layout

suvera 2022. 5. 9. 20:02

안녕하세요 오늘은 CollectionView의

Compositional Layout에 대해 알아보겠습니다. 

 

Compositional Layout은 CollectionView를 만들면서

조금 복잡한 구조를 가지게 되었을 때 유동적인 레이아웃 구성을 

할 수 있도록 도와주는 친구입니다 ! 

WWDC19에서 소개되었고, iOS 13이상에서만 지원한다고 합니다. 

 

원래 CollectionView의 레이아웃을 잡을 때 

CollectionViewFlowLayout이라는 것을 이용했었죠 ! 

 

평소에 개발을 할때 마주치는 .. 앱 구조 중 하나를 예시로 들자면

전체로 스크롤되는 큰 TableView 안의 Cell에 

CollectionView가 중첩되어있는 구조를 많이 보셨을거라 생각합니다..

 

저도 클론코딩을 하면서 이 구조를 많이 썼는데요..

코드가 굉장히 복잡해지고,, 서버통신까지 들어가게 되면 

데이터를 주고받는 과정이 굉장히 귀찮아지게 됩니다..

 

하지만 요런 구조를 Compositional Layout을 사용하여 

각 Section별로 레이아웃을 다르게 적용하여 

TableView 없이 하나의 CollectionView로 만들어 볼까 합니다 !!

 


 

UICollectionViewCompositionalLayout

위의 그림과 같이 Section, Group, item 이 3가지 컴포넌트로 구분하여

레이아웃을 구성하게 됩니다. 

 

하나씩 알아보겠습니다 !

 

1. Section - NSCollectionLayoutSection

Group을 담는 컨테이너 !

Collection View는 하나 또는 여러 개의 Section을 가질 수 있습니다.

Section은 Layout의 각각의 영역을 나타냅니다.

Section은 NSCollectionLayoutGroup에 의해 결정됩니다.

각 Section은 고유의 배경, Header, Footer를 가질 수 있습니다.

 

 

2. Group - NSCollectionLayoutGroup

 Item을 담는 컨테이너 !

  NSCollectionLayoutItem을 상속받았기 때문에 LayoutItem과 유사하게 동작합니다.

 Item을 특정 Path에 따라 배치하는 역할을 합니다.

Group 자체는 레이아웃만 배치하고 렌더링은 하지 않습니다.

  이 Group은 Section의 init(group:)에 주입됩니다.

Group은 NSCollectionLayoutDimension을 이용하여 크기를 설정할 수 있습니다.

 

 

3. Item - NSCollectionLayoutItem

Collection View의 가장 기본 컴포넌트 !

Item은 크기, 개별 content의 size, space, arrange를 어떻게 할지에 대한 blueprint입니다.

일반적으로 Item은 Cell이지만 Headers, Footers, Decorations와 같은 Supplementary View도 될 수 있습니다. 

마찬가지로 NSCollectionLayoutDimension로 크기를 결정합니다.

 이 Item은 Group에 주입됩니다.

 

// Core Concepts

let size = NSCollectionLayoutSize(widthDemension: .fractionalWidth(1.0), heightDemension: .absolute(44.0))

let item = NSCollectionLayoutItem(layoutSize: size)

let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitems: [item])

let section = NSCollectionLayoutSection(group: group)

let layout = UICollectionViewCompositionalLayout(section: section)

 

 

NSCollectionLayoutDimension

위에서 언급했던 그룹과 아이템의 크기를 결정해주는 친구 !

모든 Compositional Layout의 요소들은 크기(Size)를 갖는다고 합니다.

class NSCollectionLayoutSize {
	init(widthDimension: NSCollectionLayoutDimension,
    	heightDimension: NSCollectionLayoutDimension)
}

 

크기에는 1. width(가로길이) 와 2. height(높이) 가 있고,

NSCollectionLayoutSize의 widthDimension과 heightDimension은

일반적인 스칼라타입(ex. float)이 아닌 NSCollectionLayoutDimension타입으로 되어있습니다. 

 

방법은 3가지가 있습니다 !

 

1) absoulte : 절대 크기 , 항상 고정된 크기로 나타남

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

2) estimated : 런타임에 크기가 변할 가능성이 있는 경우(시스템의 글꼴 크기 변경과 같은) estimated를 사용!

이는 시스템이 예상 크기를 기반으로 실제 크기를 계산

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

 

3) fractional : SwiftUI에서 geomtryGeometryReader와 유사하게,

현재 자신이 속한 컨테이너의 크기를 기반으로 비율로써 자신의 크기를 정합니다.

0.0~1.0 사이의 CGFloat값을 넣을  수 있습니다.

=> 요 개념은 초면인데.. 되게 유용하다고 합니다 ! 

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

음 알아서 비율로 계산해주는거면 ! 제법 유용하겠네요 ㅎ

위의 예시같은 경우 컨테이너의 width의 20%의 width를 갖는다고 이해하시면 됩니다 !

 

+

class NSCollectionLayoutDemension {
	class func fractionalWidth(_ fractionalWidth: CGFloat) -> Self
    class func fractionalHeight(_ fractionalHeight: CGFloat) -> Self
}
let widthDimension = NSCollectionLayoutDimension.fractionalWidth(0.5)

이런식으로도 쓸수 있습니다 !

 

 

NSCollectionLayoutItem

class NSCollectioLayoutItem {
	convenience init(layoutSize: NSCollectionLayoutSize)
    var contentInsets: NSDirectionalEdgeInsets
}

 

NSCollectionLayoutGroup

Group에는 horizontal, vertical, custom 형태가 있어서 

이를 정해줄 수 있고, custom은 absolute size와 position을 구체적으로 

정해줄 수 있는 옵션입니다 !

 

NSCollectionLayoutSection

각 섹션마다 설정해 줍니다.

class NSCollectioLayouTSection {
	convenience init(layoutGroup: NSCollectionLayoutGroup)
    var contentInsets: NSDirectionalEdgeInsets
}

NSCollectionLayoutCompositionalLayout

class UICollectionViewCompositionalLayout: UICollectionViewLayout {
	init(section: NSCollectionLayoutSection)
    init(sectionProvider: @escaping SectionProvider)
}

 

 

 


예제 및 적용 

 

 

 

 

 

 

 

Apple Developer Documentation

 

developer.apple.com

 

iOS) UICollectionView custom layout에 대한 고찰- 2 (UICollectionViewCompositionalLayout)

iOS) UICollectionView custom layout에 대한 고찰- 1 (UICollectionViewFlowLayout, UICollectionViewLayout) iOS) UICollectionView custom layout에 대한 고찰- 1 (UICollectionViewFlowLayout, UIColl..

demian-develop.tistory.com

 

Comments