iOS(Swift)- UICollectionViewCompositionalLayout

JSLee·2021년 12월 21일
0

자~~이번에 알아볼것은!! 저희가 일상생활중 많은 앱들에게서 보게되는 !! UICollectionViewCompositionalLayout 입니다! 일단 이게 뭔지부터 살펴보는것이 좋겠지요?

애플 디벨로퍼 사이트에 올라온 이미지입니다!!.
위부터 쭉보면~ Section,Group,item 이 보이지요 그리고 이 한묶음이 한개 더보이고
이말을 자세히 풀어보면 Section안에~ Group이 있고~ 그안에~~Item이 있다!!
이렇게 볼수 있겠습니다!!

그럼 제가 진행중인 프로젝트를 보면서 설명하는게 빠르겠지요!!??

자 보시면 위와 아래의 cell 이 따로 놀게 되는게 보이시나요??
이게 CompositionalLayout 효과 입니다!
그럼 아까 설명한거를 빗대서 이야기해보면
저는 이 collectionView Section을 2개를 만든것입니다!
위 1개짜리 와 밑에 3개짜리 이렇게요!

그럼 일단 코드부터 살펴보겠습니다!!

class HomeCollectionViewController: UIViewController {
    //MARK: - Properties
    private lazy var collectionView : UICollectionView = {
        let layout = UICollectionViewCompositionalLayout { (sectionIndex,envi) -> NSCollectionLayoutSection? in
            switch sectionIndex {
            case 0 : return self.homeFirstCreateCompositionalLayout()
            case 1 : return self.homeSecondCreateCompositionalLayout()
            default: fatalError()
            }
        }
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout:layout)
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(HomeTopCell.self, forCellWithReuseIdentifier:HomeTopCell.identifier)
        collectionView.register(HomeCell.self, forCellWithReuseIdentifier:HomeCell.identifier)
        collectionView.register(HomeHeader.self, forSupplementaryViewOfKind: HomeHeader.identifier, withReuseIdentifier: HomeHeader.identifier)
        return collectionView
    }()

생성 입니다.보통 ViewController가 아닌 UICollectionViewController로
생성해도 더 편하다고 볼수 있어요!(저도 첨엔 컬렉션뷰컨트롤러였는데..코딩하다보니..이렇게 변하게됬네요..뷰전환~init등등..이유가 많아서 ㅎㅎ)

자그럼 본론으로!!

다른건 익숙하시죠??
근데!!

private lazy var collectionView : UICollectionView = {
        let layout = UICollectionViewCompositionalLayout { (sectionIndex,envi) -> NSCollectionLayoutSection? in
            switch sectionIndex {
            case 0 : return self.homeFirstCreateCompositionalLayout()
            case 1 : return self.homeSecondCreateCompositionalLayout()
            default: fatalError()
            }
        }

어랏 보통은 UICollectionViewFlowLayout으로 받았는데 이건뭐징!?
컬렉션뷰에 들어갈 layout을 먼저 설정 해주는 겁니다!!
반환타입이 NSCollectionLayoutSection 함수를 두개! 만들고!

    //MARK: - ConfigureCompositionalLayout(1)
    private func homeFirstCreateCompositionalLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                              heightDimension: .fractionalHeight(1))
        let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
        let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                                     heightDimension: .absolute(200))
        let layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize,
                                                             subitems: [layoutItem])
        let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
        layoutSection.orthogonalScrollingBehavior = .groupPaging
        return layoutSection
    }
    //MARK: - ConfigureCompositionalLayout(2)
    private func homeSecondCreateCompositionalLayout() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(widthDimension: .absolute(130),
                                              heightDimension: .absolute(170))
        let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)
        let layoutGroupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                                     heightDimension: .estimated(600))
        let layoutGroup = NSCollectionLayoutGroup.horizontal(layoutSize: layoutGroupSize,
                                                             subitems: [layoutItem])
        let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
        layoutSection.boundarySupplementaryItems = [.init(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(30)), elementKind: HomeHeader.identifier, alignment: .top)]
        return layoutSection
    }

요롷게 두개를 만들어 줄께요!! 왜 두개냐면요!

   func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }

CollectionView NumberOfSections함수의 return 값이 2개 거든요!!

자! 섹션의 값은 이렇게 UICollectionViewDataSource 의 내장함수인
numberOfSections에서 지정해주시면 됩니다!
섹션이 두개니깐 함수가 두개여야 겠지요??
물론 switch문등을 이용해서 좀더 짧게 만들수 있습니다

자그럼 저위에 긴~코드를 살펴보면!!

 let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1),
                                              heightDimension: .fractionalHeight(1))
        let layoutItem = NSCollectionLayoutItem(layoutSize: itemSize)

가장 안쪽의 item 입니다!
제가 생각할땐 CompositionalLayout 에서 가장 중요한건
아무래도 NSCollectionLayoutSize 아닌가 싶습니다!
하나씩 알아보면용!

absoulte : 절대값

절대 바뀌지 않는 값이에요!!무슨일이 있어요 그런데 만약 코드에서 값을 변하게 설정하게되면 당~~연 오류가 나게됩니다..저도첨에 이걸로 고생을좀..ㅎㅎㅎ

estimated : 크기가 변할경우 사용

만약 쓰레드가 시작하는도중 크기가 바뀌거나 할땐 요놈으로 사이즈를 설정하시면됩니다!!

fractional : 컨테이너 중심 크기설정.!

SwiftUI에서 geomtryGeometryReader 랑 비슷해요!!,
item은 그룹안에 있으니깐 그룹의 크기로 자신의 크기를 정합니다.
0.0~1.0 사이의 CGFloat 값으로 설정됩니다! 예를들어 1이면 그룹의 크기와 같겠죠? 백분율 같은 느낌으로 보심되겄습니다!!

자! 그럼 이제 가운데 있는

요놈들 이건 사실 버튼이에요 ㅎㅎㅎ
이것또 여러분이 자주 사용해보신적 있는 UICollectionReusableView 로 만든
Header입니다!! ㅎㅎ

평상시에 하시던것처럼 !

 func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: HomeHeader.identifier, for: indexPath) as! HomeHeader
        header.delegate = self
        return header
    }

viewForSupplementaryElementOfKind 함수를 이용해서 헤더를 받아 주셔야 됩니다 이건 같아요
그리고

 collectionView.register(HomeHeader.self, forSupplementaryViewOfKind: HomeHeader.identifier, withReuseIdentifier: HomeHeader.identifier)

register 등록도 해주셔야 됩니다!!
하지만 여기서 하나더 해주셔야될게 있어요

 let layoutSection = NSCollectionLayoutSection(group: layoutGroup)
        layoutSection.boundarySupplementaryItems = [.init(layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(30)), elementKind: HomeHeader.identifier, alignment: .top)]

이런식으로 원하는 Section을 설정할때 section에 추가를 해주셔야 됩니다.!!
그리고 alignment: 에서 원하시는 위치에 alignment 해주시면 저런식으로 되는거에요!!
아주간단하죠!! ㅎㅎㅎ

사실 제가 앱스토어를 보거나 플레이스토어 에서 앱을 보면
요즘 거의 다 이렇게 앱구성이 되있는거 같아요!! 그래서 여러분들도
UICollectionViewCompositionalLayout 을 이용한 앱을 만들어 보시는것을 추천드릴께요!!!(요즘이 아니고 옛날부터일지도...ㅎ)

감사합니다😀

깃허브

profile
iOS/Android/FE/BE

0개의 댓글