import UIKit
class ViewController: UIViewController {
// MARK: - Varaibles
let data = Array(1...20).map { "Item \($0)\\nDynamic content for size adjustment" }
// MARK: - UI Components
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
// Item 정의
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(0.5),
heightDimension: .absolute(100))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)
// Group 정의
let groupSize: NSCollectionLayoutSize
let group: NSCollectionLayoutGroup
// 섹션별 레이아웃
if sectionIndex == 0 {
// 섹션 0: 2열 레이아웃
groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(100))
group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item, item])
} else if sectionIndex == 1 {
// 섹션 1: 1열 레이아웃
groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(150))
group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
} else {
// 섹션 2: 3열 레이아웃
let tripleItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / 3.0),
heightDimension: .absolute(100))
let tripleItem = NSCollectionLayoutItem(layoutSize: tripleItemSize)
tripleItem.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)
groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(100))
group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [tripleItem, tripleItem, tripleItem])
}
// Section 정의
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 5
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
// Section 가로 스크롤 활성화
if sectionIndex == 0 {
section.orthogonalScrollingBehavior = .continuous
}
// Header 추가
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(50))
let header = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerSize,
elementKind: UICollectionView.elementKindSectionHeader,
alignment: .top
)
section.boundarySupplementaryItems = [header]
return section
}
layout.register(BackgroundDecorationView.self, forDecorationViewOfKind: "background")
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.register(SectionHeaderView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: SectionHeaderView.reuseIdentifier)
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBrown
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 10
} else if section == 1{
return 5
} else {
return 15
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .systemBlue
cell.layer.cornerRadius = 10
cell.clipsToBounds = true
// 셀 텍스트 레이블 추가
let label = UILabel(frame: cell.contentView.bounds)
label.text = data[indexPath.item]
label.numberOfLines = 0
label.textAlignment = .center
label.textColor = .white
label.font = UIFont.boldSystemFont(ofSize: 16)
label.sizeToFit()
// 중복 방지
for subview in cell.contentView.subviews {
subview.removeFromSuperview()
}
cell.contentView.addSubview(label)
return cell
}
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let header = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: SectionHeaderView.reuseIdentifier,
for: indexPath
) as! SectionHeaderView
header.configure(with: "Section \(indexPath.section + 1)")
return header
}
return UICollectionReusableView()
}
}
class BackgroundDecorationView: UICollectionReusableView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .lightGray // 원하는 배경색
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
섹션 1에만 가로 스크롤 추가:
if sectionIndex == 1 {
section.orthogonalScrollingBehavior = .continuous
}
그룹 크기 조정:
- groupSize.widthDimension을 fractionalWidth(0.8)로 설정하여 화면 너비의 80%만큼 그룹이 차지하도록 변경.
- 가로 스크롤에서는 전체 화면 너비를 넘는 그룹 크기를 가지는 것이 자연스럽습니다.
orthogonalScrollingBehavior의 값:
- .continuous: 부드럽게 스크롤.
- .paging: 페이지 단위로 스크롤.
- .groupPaging: 그룹 단위로 스크롤.
- .groupPagingCentered: 그룹 단위로 스크롤하며, 항상 화면 가운데에 표시.
🔥 item.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
contentInsets의 의미
contentInsets는 NSDirectionalEdgeInsets로 정의되며, 다음 네 가지 값을 포함합니다:
- top: 아이템의 위쪽 여백.
- leading: 아이템의 왼쪽 여백.
- bottom: 아이템의 아래쪽 여백.
- trailing: 아이템의 오른쪽 여백.
이 값들은 아이템의 컨텐츠 영역에서부터의 외부 간격을 지정합니다.
그룹 간 간격 조정
- 섹션에서 그룹 간의 간격은 section.interGroupSpacing으로 조정합니다.
section.interGroupSpacing = 5
최종 코드
import UIKit
class ViewController: UIViewController {
// MARK: - Varaibles
let data = Array(1...20).map { "Item \($0)\\nDynamic content for size adjustment" }
// MARK: - UI Components
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewCompositionalLayout { (sectionIndex, layoutEnvironment) -> NSCollectionLayoutSection? in
// Item 정의
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(100))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
item.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0)
// Group 정의
let groupSize: NSCollectionLayoutSize
let group: NSCollectionLayoutGroup
// 섹션별 레이아웃
if sectionIndex == 0 {
// 섹션 0: 2열 레이아웃
groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(100))
group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
} else if sectionIndex == 1 {
// 섹션 1: 1열 레이아웃
groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(100))
group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item])
} else {
// 섹션 2: 3열 레이아웃
let tripleItemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / 3.0),
heightDimension: .absolute(100))
let tripleItem = NSCollectionLayoutItem(layoutSize: tripleItemSize)
tripleItem.contentInsets = NSDirectionalEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)
groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(100))
group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [tripleItem, tripleItem, tripleItem])
}
// Section 정의
let section = NSCollectionLayoutSection(group: group)
section.interGroupSpacing = 10
section.contentInsets = NSDirectionalEdgeInsets(top: 1, leading: 1, bottom: 1, trailing: 1)
// Section 가로 스크롤 활성화
if sectionIndex == 0 {
section.orthogonalScrollingBehavior = .groupPagingCentered
}
// Header 추가
let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(50))
let header = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerSize,
elementKind: UICollectionView.elementKindSectionHeader,
alignment: .top
)
section.boundarySupplementaryItems = [header]
return section
}
layout.register(BackgroundDecorationView.self, forDecorationViewOfKind: "background")
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = .white
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
collectionView.register(SectionHeaderView.self,
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
withReuseIdentifier: SectionHeaderView.reuseIdentifier)
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBrown
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.topAnchor),
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor)
])
}
}
extension ViewController: UICollectionViewDataSource {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 3
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if section == 0 {
return 10
} else if section == 1{
return 5
} else {
return 15
}
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
cell.backgroundColor = .systemBlue
cell.layer.cornerRadius = 10
cell.clipsToBounds = true
// 셀 텍스트 레이블 추가
let label = UILabel(frame: cell.contentView.bounds)
label.text = data[indexPath.item]
label.numberOfLines = 0
label.textAlignment = .center
label.textColor = .white
label.font = UIFont.boldSystemFont(ofSize: 16)
label.sizeToFit()
// 중복 방지
for subview in cell.contentView.subviews {
subview.removeFromSuperview()
}
cell.contentView.addSubview(label)
return cell
}
func collectionView(_ collectionView: UICollectionView,
viewForSupplementaryElementOfKind kind: String,
at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let header = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: SectionHeaderView.reuseIdentifier,
for: indexPath
) as! SectionHeaderView
header.configure(with: "Section \(indexPath.section + 1)")
return header
}
return UICollectionReusableView()
}
}
class BackgroundDecorationView: UICollectionReusableView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .lightGray // 원하는 배경색
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
}
'UIKIT' 카테고리의 다른 글
UIScreen과 UIScene (0) | 2024.12.19 |
---|---|
setContentHuggingPriority, setContentCompressionResistancePriority (0) | 2024.12.17 |
UICollectionViewCompositionalLayout - 간단 사용 (0) | 2024.12.11 |
UIImageView를 customImageView 생성 (2) | 2024.12.04 |
상대적 경로(Relative Path)와 절대적 경로(Absolute Path)의 차이 (0) | 2024.11.25 |