본문 바로가기
iOS

[iOS] Compositional Layout 💂‍♀️

by yangsubinn 2022. 9. 5.

UICollectionViewCompositionalLayout이란?

compositionalLayout은 collectionView layout의 한 종류입니당

각각의 작은 구성들이 모여서 전체 레이아웃을 구성하는 방식으로,

기존의 컬렉션뷰 레이아웃 구현에 비해 좀 더 다양한 구성의 레이아웃을 구현할 수 있습니다.

 

section + group + item 별로 묶어서 레이아웃을 구성하기 때문에

section 별로 다른 레이아웃을 구성하기가 쉽다는 점이 장점입니다.

 

가장 작은 단위의 item부터 item을 묶어둔 group,

그 group을 묶는 section 으로 구성되어 있습니다.

item, group의 각 사이즈를 만들어주고

item은 group의 요소로, group은 section의 요소로 넣어줍니다

 

NSCollectionLayoutDimension

item, group, section의 사이즈를 정해주는 객체

 

absolute

고정된 크기 값

 

estimated

초기값을 설정해주면 런타임 후 item 사이즈에 따라 변경

 

fractionalWidth · fractionalHeight

뷰에 대한 가로·세로 비율로 결정

ex) fractionalWidth(1.0) → 뷰 가로 길이의 1.0 값

fractionalHeight(1/3) → 뷰 세로 길이의 1/3 값

 

구현을 해볼게욜

인스타그램 검색 뷰 클론코딩을 하면서 compositional layout을 사용해보게 되었어욜

func compositionalLayout() -> UICollectionViewLayout {
        // 1. item
        let squareSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1/3),
            heightDimension: .fractionalWidth(1/3))
        let squareItem = NSCollectionLayoutItem(layoutSize: squareSize)
        
        squareItem.contentInsets = NSDirectionalEdgeInsets(top: 1, leading: 1, bottom: 1, trailing: 1)
        
        // 2. group
        let squareGroupSize = NSCollectionLayoutSize(
            widthDimension: .fractionalWidth(1.0),
            heightDimension: .fractionalWidth(1/3))
        let squareGroup = NSCollectionLayoutGroup.horizontal (
            layoutSize: squareGroupSize,
            subitem: squareItem,
            count: 3)
        
        // 3. section
        let section = NSCollectionLayoutSection(group: squareGroup)
        section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
        let layout = UICollectionViewCompositionalLayout(section: section)
        return layout
}

 

section별로 다른 레이아웃 구현

홀수 섹션은 오른쪽에 세로로 긴 이미지를, 짝수 섹션은 왼쪽에 세로로 긴 이미지를 배치한 레이아웃을 구현해봤습니다. 

item(squareItem, largeItem) -> group(squareGroup, largeGroup) -> group(totalGroup) -> section

func compositionalLayout() -> UICollectionViewCompositionalLayout {
        UICollectionViewCompositionalLayout { (section, env) -> NSCollectionLayoutSection? in
            // 1. item
            let squareSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .fractionalWidth(1/3))
            let largeSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .fractionalWidth(2/3))
            
            let squareItem = NSCollectionLayoutItem(layoutSize: squareSize)
            let largeItem = NSCollectionLayoutItem(layoutSize: largeSize)
            
            squareItem.contentInsets = NSDirectionalEdgeInsets(top: 1, leading: 1, bottom: 1, trailing: 1)
            largeItem.contentInsets = NSDirectionalEdgeInsets(top: 1, leading: 1, bottom: 1, trailing: 1)
            
            // 2. group
            let squareGroupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1/3),
                heightDimension: .fractionalWidth(2/3))
            let squareGroup = NSCollectionLayoutGroup.vertical (
                layoutSize: squareGroupSize,
                subitem: squareItem,
                count: 2)
            
            let largeGroupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1/3),
                heightDimension: .fractionalWidth(2/3))
            let largeGroup = NSCollectionLayoutGroup.vertical (
                layoutSize: largeGroupSize,
                subitem: largeItem,
                count: 1)
            
						// 2-1. group 안에 group
            let totalGroupSize = NSCollectionLayoutSize(
                widthDimension: .fractionalWidth(1.0),
                heightDimension: .fractionalWidth(2/3))
            
            // 3. section에 따라 group 구성 다르게
            switch section % 2 {
            case 0:
                let totalGroup = NSCollectionLayoutGroup.horizontal (
                    layoutSize: totalGroupSize,
                    subitems: [squareGroup, squareGroup, largeGroup])

                let section = NSCollectionLayoutSection(group: totalGroup)
                section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
                return section
            default:
                let totalGroup = NSCollectionLayoutGroup.horizontal (
                    layoutSize: totalGroupSize,
                    subitems: [largeGroup, squareGroup, squareGroup])
                // 3. section
                let section = NSCollectionLayoutSection(group: totalGroup)
                section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
                return section
            }
        }
    }

 


참고자료

https://kangheeseon.tistory.com/16

https://nsios.tistory.com/150

https://ios-development.tistory.com/945