📌 결과 화면

아래와 같이 테이블뷰 안에 컬렉션뷰를 중첩한 구조를 만들려고 한다.

 

 📌 화면 구상

먼저 전체적으로 테이블뷰를 넣고 테이블뷰셀 안에 컬렉션뷰를 넣어주는 식으로 작업했다.

 

왼쪽부터 TV를 넣어준 SB, TVC(안에 CV) xib, CVC xib이다.

 

 📌 코드 - TV 설정

TV가 있는 스토리보드와 연결한 뷰컨트롤러 파일을 열어준다.

이후 스토리보드의 TV를 IBOutlet으로 연결해준다.

@IBOutlet weak var postTV: UITableView!

 

그리고 TVC를 등록하고 TVC의 delegate와 dataSource를 self로 설정해준다.

나는 해당 코드를 함수로 묶어 viewDidLoad에 넣어주었다.

private func setPostTV() {
    postTV.register(UINib(nibName: "PostTVC", bundle: nil), forCellWithReuseIdentifier: "PostTVC")
    postTV.delegate = self
    postTV.dataSource = self
}

 

UITableViewDelegate와 UITableViewDataSource 각각 코드를 작성해준다.

// MARK: - UITableViewDelegate
extension CreateMainVC: UITableViewDelegate {
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        /// 만약 서버통신 후 받아온 각각의 게시글의 이미지 개수가 2개이면 iPhone 13 mini 기준 높이를 268, 3개이면 207로 설정해준다.
        let height = (postList[indexPath.row].images.count == 2) ? 268 : 207
        
        return height
    }
}

// MARK: - UITableViewDataSource
extension CreateMainVC: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        /// 총 TVC의 개수는 서버 통신 후 받아온 게시글의 총 개수
        return postList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: PostTVC.className, for: indexPath) as? PostTVC else { return UITableViewCell() }
        
        /// 순서대로 데이터 넣어주기
        /// TVC에 작성해준 setData 함수를 활용한다. 이때 CV를 위한 이미지 리스트도 전달한다.
        cell.setData(postList[indexPath.row])
        
        return cell
    }
}

 

 📌 코드 - TVC 설정

TVC xib파일과 연결한 UITableViewCell 파일을 열어준다.

이후 xib의 CV를 IBOutlet으로 연결해준다.

@IBOutlet weak var imgCV: UICollectionView!

 

그리고 CVC를 등록하고 CVC의 delegate와 dataSource를 self로 설정해준다.

나는 해당 코드를 함수로 묶어 viewDidLoad에 넣어주었다.

private func setImgCV() {
    imgCV.register(UINib(nibName: "ImgCVC", bundle: nil), forCellWithReuseIdentifier: "ImgCVC")
    imgCV.delegate = self
    imgCV.dataSource = self
}

그리고 TVC를 등록하고 TVC의 delegate와 dataSource를 self로 설정해준다.

나는 해당 코드를 함수로 묶어 viewDidLoad에 넣어주었다.

 

마지막으로 UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout 각각 코드를 작성해준다.

TV에서 setData함수를 통해 넘겨준 데이터 중 imgList를 활용한다.

// MARK: - UICollectionViewDelegate
extension PostTVC: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        /// CVC 개수는 이미지 개수와 같다.
        return imgList.count
    }
}

// MARK: - UICollectionViewDataSource
extension PostTVC: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ImgCVC.className, for: indexPath) as? ImgCVC else {
            return UICollectionViewCell()
        }
        /// CVC에 작성해준 setData 함수를 활용한다.
        cell.setData(imgList[indexPath.row])
        
        return cell
    }
}

// MARK: - UICollectionViewDelegateFlowLayout
extension PostTVC: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        /// 게시글 이미지 개수에 따라 너비와 높이를 정해준다.
        let cellWidth = (imgList.count == 2) ? 163 : 104
        let cellHeight = (imgList.count == 2) ? 170 : 109
        
        return CGSize(width: cellWidth, height: cellHeight)
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
        /// 게시글의 이미지 개수에 따라 인셋을 정해준다.
        if imgList.count == 2 {
            return UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
        } else {
            return UIEdgeInsets(top: 12, left: 18, bottom: 12, right: 18)
        }
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        /// 게시글의 이미지 개수에 따라 CVC간 간격을 정해준다.
        let spacingSize = (imgList.count == 2) ? 17 : 14
        
        return CGFloat(spacingSize)
    }
}

 

+ Recent posts