처음 팀프로젝트가 시작됐다. 기대했던 프로젝트 였기에 떨리고 긴장되는 마음이었는데 진행될 수록 팀원들 덕분에 착착 순조롭게 진행되는 것 같아 점점 더 재밌어지는 것 같다
이 프로젝트가 진행되는 일지를 적어보려고 한다.
우리팀은 키오스크 만들기 중 애플 제품을 판매하는 앱을 만드는 것을 방향으로 잡고 각자의 역할을 분담에 맡았다.
나는 그 중 세그먼트 컨트롤러를 이용해 각 세그별로 컬렉션 뷰로 제품을 나열하는 기능을 구현하는 것을 맡았다.
Model 생성
먼저 데이터 모델을 만들어주자
struct AppleProduct {
let image: UIImage?
let name: String
let price: Int
let category: String
}
내가 컬렉션 뷰에 보여줄 데이터와 그것을 분류해 줄 카테고리를 만들기 위해 이렇게 데이터 모델을 구성했다.
class DataManager {
var products: [AppleProduct] = []
init() {
// 제품 데이터 초기화 및 추가
}
}
그리고 데이터 매니저 클래스를 생성하여 컬렉션 뷰 안에 들어갈 데이터를 넣어주었다.
View 생성
제품을 표시할 컬렉션 뷰 셀을 ProductCell로 지정하고 컬렉션 뷰 내 들어갈 컬렉션 셀을 코드로 작성해 넣었다. 원래는 스토리보드로 들어가 있었지만 스토리보드 오토레이아웃이 계속 꼬이는 바람에 그냥 지우고 코드로 다시 작성하게 되었다.
먼저 데이터를 넣어줄 이미지와 레이블을 생성했다.
// 이미지 뷰
let productImage: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.clipsToBounds = true
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
// 제품 이름 레이블
let productLabel: UILabel = {
let label = UILabel()
label.font = UIFont.boldSystemFont(ofSize: 18)
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
// 제품 가격 레이블
let productPrice: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 14)
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
그 다음 이 생성된 컴포넌트들을 오토레이아웃을 잡아주었다.
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(productImage)
addSubview(productLabel)
addSubview(productPrice)
NSLayoutConstraint.activate([
productImage.topAnchor.constraint(equalTo: topAnchor),
productImage.leadingAnchor.constraint(equalTo: leadingAnchor),
productImage.trailingAnchor.constraint(equalTo: trailingAnchor),
productImage.heightAnchor.constraint(equalToConstant: 150),
productImage.widthAnchor.constraint(equalToConstant: 150),
productLabel.topAnchor.constraint(equalTo: productImage.bottomAnchor, constant: 8),
productLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
productLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8),
productPrice.topAnchor.constraint(equalTo: productLabel.bottomAnchor, constant: 4),
productPrice.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8),
productPrice.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8),
productPrice.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
그 이후 제품 데이터를 만들어준 컴포넌트 내 넣어주는 식을 작성하였다.
func configure(with product: AppleProduct) {
productImage.image = product.image
productLabel.text = product.name
// 가격 포맷팅 및 표시
}
이렇게 까지 해서 Model 과 View 의 구성을 마치게 되었고 그다음엔 컨트롤러를 설정해준다
Controller 생성
let dataManager = DataManager()
let cellMarginSize: CGFloat = 2.0
var filteredProducts: [AppleProduct] = [] {
didSet {
mainCollectionView.reloadData()
}
}
데이터를 컨트롤러에 가져와 컬렉션뷰의 변화가 있을 때마다 didSet 을 통해 데이터가 리로드 될 수 있도록 코드를 구현해주도록 한다.
mainCollectionView.dataSource = self
mainCollectionView.delegate = self
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return filteredProducts.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ProductCell", for: indexPath) as! ProductCell
let product = filteredProducts[indexPath.item]
cell.configure(with: product)
return cell
}
}
그 이후 이전 테이블 뷰에서 했던 것과 마찬가지로 컬렉션뷰도 동일하게 델리게이트를 선언하고 데이터 소스를 가져와야한다.
지금 나온 두가지 필수 구현사항은 이전 테이블 뷰에서 많이 접했던 내용으로 익숙했다.
numberOfItemsInSection 은 셀의 갯수를 지정하는 것으로 filteredProducts 즉 세그먼트를 통해 필터링 된 해당하는 카테고리에 맞는 데이터의 갯수를 가져왔다.
cellForItemAt 은 각 셀을 생성하고 재사용 가능한 셀을 가져와 데이터 모델을 해당 셀과 연결하고 반환한다.
그 이후 이제 세그먼트 컨트롤러와 컬렉션 뷰의 데이터를 연결하여 필터링된 데이터를 확인할 수 있도록 구현해보자
@IBAction func segmentValueChanged(_ sender: UISegmentedControl) {
switch sender.selectedSegmentIndex {
case 0:
filteredProducts = dataManager.products.filter { $0.category == "맥북" }
case 1:
filteredProducts = dataManager.products.filter { $0.category == "아이폰" }
case 2:
filteredProducts = dataManager.products.filter { $0.category == "패드" }
case 3:
filteredProducts = dataManager.products.filter { $0.category == "워치" }
case 4:
filteredProducts = dataManager.products.filter { $0.category == "악세사리" }
default:
break
}
mainCollectionView.reloadData()
}
먼저 미리 스토리보드에 구현된 세그먼트컨트롤러를 IBAction 으로 가져와 세그먼트의 인덱스 즉 각 카테고리별로 눌렸을때 데이터의 카테고리를 통해 필터링 된 값을 가질 수 있도록 코드를 구현했다.
지금 여기까지 과정을 순탄하게 진행할 수 있었으나, 그 이후 컬렉션뷰의 크기를 지정하는 것에 오류가 생겨 자꾸 데이터가 셀에 제대로 보이지 않아 애를 먹었다.
컬렉션 뷰 셀의 크기를 지정하고 그안에 세부적인 변동사항을 지정하고 싶을 땐
바로 컬렉션 뷰의 FlowLayout 을 설정해주어야 한다.
func createFlowLayout() -> UICollectionViewFlowLayout {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 150, height: 100)
layout.estimatedItemSize = CGSize(width: 160, height: 200)
layout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
return layout
}
createFlowLayout 메서드를 만들어 UICollectionViewFlowLayout 를 생성하고 설정한다.
수직으로 스크롤이 되도록 설정하고 각 셀의 크기를 설정했다.
그 이후 sectionInset 를 통해 각 셀의 내부 여백을 맞춰주니 다행히 원했던 뷰가 만들어졌다..
이 과정이 가장 어렵고 힘든 과정이었다 ㅠㅠ
이렇게 만들어진 createFlowLayout 를 적용할 수 있도록 뷰디드로드에 해당 값을 넣어준다.
let flowLayout = createFlowLayout()
mainCollectionView.collectionViewLayout = flowLayout
이렇게 완료하면 구현은 완료!
팀원들에게 많은 도움을 받아 생각보다 수월하게 진행할 수 있었다. 이렇게 진행된 내용을 기록하며 내가 부족한 점과 알게된 점을 기록하도록 하자 🙂
지금까지 진행된 내용을 다른 분들과 공유하여 머지를 한 지금까지의 결과이다.
추가적으로 넣을만한 기능을 생각해 적용해볼 생각이다.
'◽️ Programming > T I L' 카테고리의 다른 글
[ProJect 일지] 키오스크 (3) (Compositional Layout) (0) | 2024.04.04 |
---|---|
[ProJect 일지] 키오스크 (2) (0) | 2024.04.03 |
Delegate 패턴과 Notification 의 차이 및 특징 (1) | 2024.03.29 |
ToDoList 만들기 (5) 캘린더 추가 (0) | 2024.03.28 |
ToDoList 앱 만들기 (4) (1) | 2024.03.27 |