IOS - Swift
[iOS/Swift] 앱스토어 게임 탭 따라하기 (Composition Layout)
게게겍
2023. 10. 1. 16:50
구현하려는 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