오전, 오후 시간 각각의 영화 시간대가 출력되는 각각의 컬렉션 뷰를 구성하고 있었다.
오전, 오후라는 제목을 넣고 싶어서 처음에는 다음과 같이 라벨 2개와 컬렉션 뷰 2개를 구성했었다.
@IBOutlet weak var morningLabel: UILabel!
@IBOutlet weak var morningCollectionView: UICollectionView!
@IBOutlet weak var afternoonLabel: UILabel!
@IBOutlet weak var afternoonCollectionView: UICollectionView!
2개의 컬렉션 뷰 중 하나의 셀만 선택하여 스타일을 변경 후 표시해주고 싶었는데 여러 방법을 시도해봐도 처리가 어려웠다.
▼ 시도 방법 확인하기
시도 방법 1. 이전 선택한 셀의 스타일을 초기화
// MARK: - UICollectionViewDelegat
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// 이전에 선택된 셀의 배경색 초기화
if let previousSelectedIndexPath = selectedIndexPath {
if let previousCell = collectionView.cellForItem(at: previousSelectedIndexPath) {
previousCell.contentView.backgroundColor = .clear
}
}
// 선택된 셀의 배경색 변경
if let selectedCell = collectionView.cellForItem(at: indexPath) {
selectedCell.contentView.backgroundColor = .green
}
// 선택된 셀의 인덱스 저장
selectedIndexPath = indexPath
}
시도 방법 2. 모든 셀의 선택 상태를 해제
// MARK: - UICollectionViewDelegat
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// 모든 셀의 선택 상태를 해제
for index in 0..<collectionView.numberOfItems(inSection: 0) {
let indexPath = IndexPath(item: index, section: 0)
collectionView.deselectItem(at: indexPath, animated: false)
}
// 선택된 셀의 스타일 변경
if let cell = collectionView.cellForItem(at: indexPath) {
cell.isSelected = true
cell.contentView.backgroundColor = .green // 스타일 적용
}
// 선택된 셀의 인덱스 저장
selectedIndexPath = indexPath
}
시도 방법 3. 선택된 셀의 IndexPath를 저장하여 선택되지 않은 컬렉션뷰의 선택 해제 후 리로드
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// 선택된 셀의 IndexPath 저장
if collectionView == morningCollectionView {
selectedIndexPathForMorning = indexPath
selectedIndexPathForAfternoon = nil // 오전 시간대의 선택이 있을 때는 오후 시간대의 선택 해제
} else if collectionView == afternoonCollectionView {
selectedIndexPathForAfternoon = indexPath
selectedIndexPathForMorning = nil // 오후 시간대의 선택이 있을 때는 오전 시간대의 선택 해제
}
// 컬렉션 뷰 리로드
collectionView.reloadData()
}
이전에 선택된 셀을 찾아 스타일을 해제해봐도,
데이터가 변경될 때 셀을 다시 로드해줘도,, 같은 문제가 계속 발생했다 !!
결국 하나의 셀만 선택되지 않는 문제가 발생한 것인데 그 이유는 두 개의 컬렉션 뷰가 각각의 셀 선택을 관리하려고 시도하기 때문이다!
그래서 결국 컬렉션 뷰 2개를 이용해서 구현하는 방식을 바꾸기로 결정했다.
2개로 나누는 것보다는 하나의 컬렉션 뷰로 구성해야 더 효율적인 것 같아
오전 오후의 시간대를 나누기 위해 섹션을 나누는 방법 중 알아낸 것은 헤더를 추가하는 것이었다.
헤더란?
컬렉션뷰의 헤더는 컬렉션뷰의 섹션(그룹) 위에 표시되는 영역이다.
일반적으로 섹션의 제목이나 추가 정보를 표시하는 데 사용된다.
헤더는 섹션의 시작 부분에 위치하며, 섹션과 관련된 데이터를 시각적으로 나타내는 데 도움이 된다.
셀과 유사하게 추가할 수 있는데 조금 차이가 있다.
- Cell -> UICollectionViewCell
- Header -> UICollectionReusableView
UICollectionReusableView를 사용해서 만들 수 있고 헤더를 커스텀하는 방식은 기존 cell처럼 UICollectionViewDelegateFlowLayout에서 조정할 수 있다.
이후 헤더를 collectionView에 register하고 불러와 사용하면 된다!
해결 방법
그래서 헤더를 공부한 후 문제를 해결한 방법으로는
두 개의 컬렉션 뷰 대신 하나의 컬렉션 뷰를 사용하여 모든 시간을 표시하고, 각각의 시간을 "오전"과 "오후"로 나누는 헤더를 추가하는 것이었다. 이렇게 하면 하나의 컬렉션 뷰에서만 셀 선택을 관리하면 되기 때문에 여러 개의 셀이 선택되는 문제가 해결되었다.
컬렉션뷰Cell과 동일하게 Header 등록하기
func register() {
timeCollectionView.register(UINib(nibName: "TimeCell", bundle: nil), forCellWithReuseIdentifier: "TimeCell")
timeCollectionView.register(UINib(nibName: "HeaderView", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
}
UICollectionViewDelegateFlowLayout으로 헤더뷰 설정하기
// MARK: - UICollectionViewDelegateFlowLayout
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: 50) // 헤더 높이 설정
}
func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
if kind == UICollectionView.elementKindSectionHeader {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
// 헤더 뷰 설정
headerView.titleLabel.text = indexPath.section == 0 ? "오전" : "오후"
return headerView
} else {
return UICollectionReusableView()
}
}
👉 다음과 같이 collectionView(_:viewForSupplementaryElementOfKind:at:)를 사용하여 헤더를 구성했다.
이렇게 하면 하나의 컬렉션 뷰에 두 개의 섹션을 가진 구조를 만들어 각각의 섹션에 "오전"과 "오후"를 표시할 수 있게 된다!
빌드를 해서 확인해보면 원하는 대로 컬렉션 뷰에 각 섹션 헤더가 추가된 걸 확인할 수 있다.
원래 구현 목적이었던 선택한 셀의 스타일을 변경하는 코드를 구성해보자.
이제 간단히 작성해볼 수 있다.
didSelectItemAt()
// MARK: - UICollectionViewDelegate
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
// 선택된 셀의 스타일 변경
if let cell = collectionView.cellForItem(at: indexPath) as? TimeCell {
cell.borderView.backgroundColor = .systemIndigo
print("Selected time: \(cell.titleLabel.text ?? "")")
selectedTime = cell.titleLabel.text ?? ""
}
// 이전에 선택된 셀이 있다면 선택 해제
if collectionView == collectionView {
if let selectedIndexPath = selectedIndexPath {
if let cell = collectionView.cellForItem(at: selectedIndexPath) as? TimeCell {
cell.borderView.backgroundColor = .clear // 이전에 선택된 셀의 스타일 초기화
}
}
}
// 선택된 셀의 인덱스 저장
selectedIndexPath = indexPath
}
선택된 셀의 배경색을 변경하여 강조해준다.
또한 이전에 선택된 셀이 있다면 선택을 해제하고, 마지막으로 선택된 셀의 인덱스를 저장한다.
이제 처음에 셀의 스타일 변경여러개가 선택되어 골치아팠던 문제가 잘 해결되었다 ㅎㅎ!
헤더를 사용해서 섹션을 구분할 수 있어 원래 구성하려고 했던 2개의 컬렉션 뷰 구성보다
구조가 더 깔끔하고 중복되는 코드들도 줄어들었다.
'TIL✏️' 카테고리의 다른 글
[iOS] 알람 앱 (1) - TabBarItem, NavigationBarItem 이미지 추가하기 (10) | 2024.05.13 |
---|---|
[iOS] 책 검색 & 저장 App (1) - Kakao REST API 사용해서 책 검색하기 (4) | 2024.05.07 |
[iOS] WishList App - ScrollView 적용, Pull to Refresh (4) | 2024.04.18 |
[iOS] WishList App - CoreData 사용하기 (2) | 2024.04.17 |
[iOS] WishList App - URLSession 으로 API 연결하기 (2) | 2024.04.16 |