[iOS/Swift] 앱스토어 게임 탭 따라하기 (Composition Layout)

2023. 10. 1. 16:50·IOS - Swift
반응형

구현하려는 view

 

 

Compositional layout

 

 

각 필요한 Cell들을 Nib 파일로 묶어서 작성했습니다.

import UIKit

final class ExtraLargeAppCell: UICollectionViewCell {
    @IBOutlet private var captionLabel: UILabel!
    @IBOutlet private var titleLabel: UILabel!
    @IBOutlet private var subtitleLabel: UILabel!
    @IBOutlet private var thumbnailView: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()
        thumbnailView.layer.cornerRadius = 4
    }
}

다음으로 Compositional Layout에 필요한 기본 값들을 Protocol로 선언하여 기본 Section값을 할당합니다.

import UIKit

protocol Sections {
    var numberOfItem: Int { get }
    func layoutSection() -> NSCollectionLayoutSection
    func configureCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell

}

다양한 section들의 기본 값입니다. 고정값이 아닌 상대값으로 layout값을 맞춥니다.

import UIKit

struct FeaturedAppSection: Sections {
    
    let numberOfItem = 5

    func layoutSection() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.92), heightDimension: .fractionalHeight(0.4))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .groupPagingCentered

        return section
    }
    
    func configureCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: SectionTitleCell.self), for: indexPath)
        return cell
    }
}

호출할 viewController입니다.

import UIKit

final class GamesViewController: UIViewController {
    
    lazy var sections: [Sections] = [ // 불러오기
        FeaturedAppSection(),
        SectionTitleSection(),
        SmallAppSection(),
        SectionTitleSection(),
        MediumAppSection(),
        SectionTitleSection(),
        TodayGameSection(),
        CategorySection(),
        SectionTitleSection(),
        SectionTitleSection(showsNavigation: false),

    ]

    lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
        collectionView.backgroundColor = .systemBackground
        collectionView.dataSource = self
        collectionView.delegate = self
        
        
        collectionView.register(UINib(nibName: String(describing: SmallAppCell.self), bundle: nil),forCellWithReuseIdentifier: String(describing: SmallAppCell.self))
        collectionView.register(UINib(nibName: String(describing: MediumAppCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: MediumAppCell.self))
        collectionView.register(UINib(nibName: String(describing: ExtraLargeAppCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: ExtraLargeAppCell.self))

        collectionView.register(UINib(nibName: String(describing: CategoryCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: CategoryCell.self))
        collectionView.register(UINib(nibName: String(describing: SectionTitleCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: SectionTitleCell.self))

        
        return collectionView
    }()
    lazy var collectionViewLayout: UICollectionViewLayout = {
        var sections = self.sections
        let layout = UICollectionViewCompositionalLayout { (sectionIndex, environment) -> NSCollectionLayoutSection? in
            return sections[sectionIndex].layoutSection()
        } 
        return layout
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(collectionView)

        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
    }

}

extension GamesViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        sections.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return sections[section].numberOfItem
        
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return sections[indexPath.section].configureCell(collectionView: collectionView, indexPath: indexPath)
    }
}

extension GamesViewController: UICollectionViewDelegate {}

각 필요한 Cell들을 Nib 파일로 묶어서 작성했습니다.

import UIKit

final class ExtraLargeAppCell: UICollectionViewCell {
    @IBOutlet private var captionLabel: UILabel!
    @IBOutlet private var titleLabel: UILabel!
    @IBOutlet private var subtitleLabel: UILabel!
    @IBOutlet private var thumbnailView: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()
        thumbnailView.layer.cornerRadius = 4
    }
}

다음으로 Compositional Layout에 필요한 기본 값들을 Protocol로 선언하여 기본 Section값을 할당합니다.

import UIKit

protocol Sections {
    var numberOfItem: Int { get }
    func layoutSection() -> NSCollectionLayoutSection
    func configureCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell

}

다양한 section들의 기본 값입니다. 고정값이 아닌 상대값으로 layout값을 맞춥니다.

import UIKit

struct FeaturedAppSection: Sections {
    
    let numberOfItem = 5

    func layoutSection() -> NSCollectionLayoutSection {
        let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
        let item = NSCollectionLayoutItem(layoutSize: itemSize)

        let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.92), heightDimension: .fractionalHeight(0.4))
        let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])

        let section = NSCollectionLayoutSection(group: group)
        section.orthogonalScrollingBehavior = .groupPagingCentered

        return section
    }
    
    func configureCell(collectionView: UICollectionView, indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: SectionTitleCell.self), for: indexPath)
        return cell
    }
}

호출할 viewController입니다.

import UIKit

final class GamesViewController: UIViewController {
    
    lazy var sections: [Sections] = [ // 불러오기
        FeaturedAppSection(),
        SectionTitleSection(),
        SmallAppSection(),
        SectionTitleSection(),
        MediumAppSection(),
        SectionTitleSection(),
        TodayGameSection(),
        CategorySection(),
        SectionTitleSection(),
        SectionTitleSection(showsNavigation: false),

    ]

    lazy var collectionView: UICollectionView = {
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
        collectionView.backgroundColor = .systemBackground
        collectionView.dataSource = self
        collectionView.delegate = self
        
        
        collectionView.register(UINib(nibName: String(describing: SmallAppCell.self), bundle: nil),forCellWithReuseIdentifier: String(describing: SmallAppCell.self))
        collectionView.register(UINib(nibName: String(describing: MediumAppCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: MediumAppCell.self))
        collectionView.register(UINib(nibName: String(describing: ExtraLargeAppCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: ExtraLargeAppCell.self))

        collectionView.register(UINib(nibName: String(describing: CategoryCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: CategoryCell.self))
        collectionView.register(UINib(nibName: String(describing: SectionTitleCell.self), bundle: nil), forCellWithReuseIdentifier: String(describing: SectionTitleCell.self))

        
        return collectionView
    }()
    lazy var collectionViewLayout: UICollectionViewLayout = {
        var sections = self.sections
        let layout = UICollectionViewCompositionalLayout { (sectionIndex, environment) -> NSCollectionLayoutSection? in
            return sections[sectionIndex].layoutSection()
        } 
        return layout
    }()

    override func viewDidLoad() {
        super.viewDidLoad()

        collectionView.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(collectionView)

        NSLayoutConstraint.activate([
            collectionView.topAnchor.constraint(equalTo: view.topAnchor),
            collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)])
    }

}

extension GamesViewController: UICollectionViewDataSource {
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        sections.count
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return sections[section].numberOfItem
        
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        return sections[indexPath.section].configureCell(collectionView: collectionView, indexPath: indexPath)
    }
}

extension GamesViewController: UICollectionViewDelegate {}

 

참고

 

GitHub - kishikawakatsumi/AppStore-Clone-CollectionViewCompositionalLayouts: Sample project for implementing App Store.app UI wi

Sample project for implementing App Store.app UI with Collection View Compositional Layouts - GitHub - kishikawakatsumi/AppStore-Clone-CollectionViewCompositionalLayouts: Sample project for impleme...

github.com

 

반응형

'IOS - Swift' 카테고리의 다른 글

[iOS/Swift] Missing file libarclite_iphoneos.a (Xcode 15)오류 해결  (0) 2024.01.11
[iOS/Swift] 앱스토어 배포와 리젝일기  (0) 2023.10.29
[iOS/Swift] BottomSheet 구현하기 - 라이브러리 사용  (1) 2023.09.10
[iOS/Swift] Run Loop ( 2 / 2 )  (1) 2023.08.27
[iOS/Swift] Run Loop - (1 / 2)  (0) 2023.08.20
'IOS - Swift' 카테고리의 다른 글
  • [iOS/Swift] Missing file libarclite_iphoneos.a (Xcode 15)오류 해결
  • [iOS/Swift] 앱스토어 배포와 리젝일기
  • [iOS/Swift] BottomSheet 구현하기 - 라이브러리 사용
  • [iOS/Swift] Run Loop ( 2 / 2 )
게게겍
게게겍
열심히 공부해보고 있습니다
  • 게게겍
    코더라도 되어보자
    게게겍
  • 전체
    오늘
    어제
    • 분류 전체보기
      • IOS - Swift
        • UIkit
        • SwiftUI
        • Combine
      • 혼자 공부한거
      • inflearn
      • 기타
      • 일기
      • firebase
      • CS
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    UIHostingController
    open
    trymap
    UIViewRepresentable
    combine
    launchscreen
    private
    ios
    replacemap
    map
    INTERNAL
    UICollectionView Custom Cell with Horizontal Scroll
    subscription
    uikit
    #GDSC #캐치카페 #대관 # 대학생 #취준생 #진학사
    flatMap
    viewBuilder
    compactMap
    scan
    fileprivate
    SwiftUI
    Swift
    swift openapigenerator
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
게게겍
[iOS/Swift] 앱스토어 게임 탭 따라하기 (Composition Layout)
상단으로

티스토리툴바