일반적으로 UIScrollView 안에 UITableView를 넣는 것은 권장되지 않습니다.
이유는 두 개의 스크롤 기능이 충돌할 수 있기 때문입니다.
❌ 문제점
- 스크롤 충돌
- UIScrollView와 UITableView 모두 수직 스크롤이 가능하기 때문에, 터치 이벤트가 어디로 전달될지 애매해질 수 있음.
- 예를 들어, UIScrollView가 스크롤을 가로채거나, UITableView가 제대로 스크롤되지 않는 문제 발생 가능.
- UITableView의 contentSize 문제
- UITableView는 자체적으로 contentSize를 계산하여 스크롤을 조정함.
- UIScrollView 안에 들어가면 UITableView가 자신의 높이를 자동으로 조절하지 못할 수 있음.
- 스크롤 동작이 이상해질 가능성
- UIScrollView가 UITableView의 스크롤을 방해하거나, 반대로 UITableView가 UIScrollView의 스크롤을 막을 수도 있음.
✅ 어떻게 하면 될까? (해결 방법)
1️⃣ 스크롤뷰를 사용하지 않고 UITableView 자체를 활용하는 방법 (추천)
- 만약 UITableView 안에 여러 가지 섹션이 필요하다면, 헤더, 푸터, 셀을 활용하여 동적인 UI를 구성하는 것이 가장 좋음.
- UITableView는 이미 스크롤 기능을 가지고 있으므로 추가적인 UIScrollView가 필요 없음.
🔥 이 방법이 가장 안정적이고 일반적으로 권장되는 방법입니다.
2️⃣ UIScrollView 안에 UITableView를 넣어야 한다면?
- UITableView의 높이를 미리 계산하여 고정하고 UIScrollView 안에 배치해야 함.
- UITableView가 전체 높이를 가지도록 heightAnchor를 설정하여 UIScrollView 내에서 정상적으로 스크롤되도록 처리.
🔥 결론
- 가장 좋은 방법: UITableView 자체를 사용하여 스크롤뷰를 대체하고, headerView, footerView, section을 활용하여 동적 UI를 구성.
- UIScrollView 안에 UITableView를 넣어야 한다면, UITableView의 높이를 고정하고, isScrollEnabled = false 설정하여 UIScrollView가 정상적으로 스크롤되도록 처리해야 함.
⚠️ UIScrollView 안에 UITableView를 넣는 것은 일반적으로 비효율적이며, 특별한 경우에만 사용해야 함! 🚀
1️⃣ UIScrollView를 사용할 경우 (비효율적인 경우)
🔹 구현 방식
- UIScrollView를 생성하고, 그 안에 UIView를 넣고,
그 안에 여러 개의 UILabel, UICollectionView, UIImageView 등을 배치하여 스크롤 가능하도록 구현. - contentSize를 동적으로 조절해야 하고, 내부의 콘텐츠가 많아질수록 레이아웃 관리가 어려워짐.
🔸 단점
❌ 성능 이슈: UIScrollView는 모든 데이터를 한 번에 로드해야 해서, 데이터가 많아지면 성능이 저하될 수 있음.
❌ 재사용 불가능: UIScrollView 내에서 각각의 UIView를 관리해야 하므로 메모리 낭비가 발생할 수 있음.
❌ 동적 높이 조절 문제: UILabel 같은 요소들의 높이를 동적으로 조절해야 하는 경우, 제약 조건이 복잡해지고 레이아웃이 깨질 가능성이 있음.
✅ UIScrollView는 상세 페이지가 매우 간단한 경우(예: 텍스트 몇 개, 이미지 하나)에는 사용할 수 있지만,
일반적으로 영화 상세 페이지처럼 데이터가 많다면 UITableView를 사용하는 것이 더 적합함. 🚀
private func configureConstraints() {
addSubview(basicScrollView)
basicScrollView.addSubview(basicView)
basicView.addSubview(backdropImage)
basicView.addSubview(posterImage)
basicView.addSubview(titleLabel)
basicView.addSubview(releasedDateLabel)
basicView.addSubview(adultSignImage)
basicScrollView.translatesAutoresizingMaskIntoConstraints = false
basicView.translatesAutoresizingMaskIntoConstraints = false
backdropImage.translatesAutoresizingMaskIntoConstraints = false
posterImage.translatesAutoresizingMaskIntoConstraints = false
titleLabel.translatesAutoresizingMaskIntoConstraints = false
releasedDateLabel.translatesAutoresizingMaskIntoConstraints = false
adultSignImage.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
...
])
}
2️⃣ UITableView를 사용할 경우 (실무에서 주로 사용하는 방식)
🔹 구현 방식
- UITableView를 생성하고, 각 항목을 섹션으로 나누어 관리.
- 예를 들면:
- 🎬 헤더 섹션: 영화 포스터, 배경 이미지, 제목, 개봉일, 평점 (UITableViewHeaderView)
- 📝 줄거리 섹션: 영화의 개요 (UITableViewCell)
- 🎭 출연진 섹션: 출연 배우 리스트 (UICollectionView 포함)
- 🎞 관련 영화 섹션: 비슷한 영화 추천 리스트 (UICollectionView 포함)
- 🎤 사용자 리뷰 섹션: 사용자들이 남긴 리뷰 (UITableViewCell)
🔸 장점
✅ 재사용성: UITableViewCell과 UICollectionViewCell을 활용하여 메모리를 효율적으로 관리 가능.
✅ 동적 레이아웃 가능: UITableView의 automaticDimension을 사용하면, 내용에 맞게 높이를 자동 조절 가능.
✅ 퍼포먼스 최적화: 스크롤 시 필요한 부분만 로드되므로 메모리 절약.
✅ 코드 유지보수 용이: UITableViewDataSource와 UITableViewDelegate를 활용하여 데이터를 분리하여 관리 가능.
🚀 대부분의 실무에서는 UITableView 기반으로 영화 상세 페이지를 만듦.
import UIKit
class MovieDetailViewController: UIViewController {
private let tableView: UITableView = {
let tableView = UITableView(frame: .zero, style: .grouped)
tableView.separatorStyle = .none
return tableView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .black
setupTableView()
}
private func setupTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.register(MovieHeaderTableViewCell.self, forCellReuseIdentifier: MovieHeaderTableViewCell.reuseIdentifier)
tableView.register(MovieOverviewTableViewCell.self, forCellReuseIdentifier: MovieOverviewTableViewCell.reuseIdentifier)
tableView.register(MovieCastTableViewCell.self, forCellReuseIdentifier: MovieCastTableViewCell.reuseIdentifier)
tableView.register(MovieSimilarTableViewCell.self, forCellReuseIdentifier: MovieSimilarTableViewCell.reuseIdentifier)
view.addSubview(tableView)
tableView.frame = view.bounds
}
}
extension MovieDetailViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 4 // 🎬 헤더, 📝 줄거리, 🎭 출연진, 🎞 관련 영화
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1 // 각 섹션에 하나의 셀만 존재
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: MovieHeaderTableViewCell.reuseIdentifier, for: indexPath) as! MovieHeaderTableViewCell
cell.configure(movie)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: MovieOverviewTableViewCell.reuseIdentifier, for: indexPath) as! MovieOverviewTableViewCell
cell.configure(movie.overview)
return cell
case 2:
let cell = tableView.dequeueReusableCell(withIdentifier: MovieCastTableViewCell.reuseIdentifier, for: indexPath) as! MovieCastTableViewCell
cell.configure(movie.cast)
return cell
case 3:
let cell = tableView.dequeueReusableCell(withIdentifier: MovieSimilarTableViewCell.reuseIdentifier, for: indexPath) as! MovieSimilarTableViewCell
cell.configure(movie.similarMovies)
return cell
default:
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension // 셀의 높이를 내용에 맞게 자동 조절
}
}
'Project > MovieClip' 카테고리의 다른 글
테이블의 rowheight을 동적으로 할 때 주의할 점 (0) | 2025.02.10 |
---|---|
TMDB에서 특정 조건의 video 정보 받아오기 (0) | 2025.02.10 |
셀 재사용으로 인한 이전 데이터 표시되는 문제 (0) | 2025.02.08 |
상세페이지로 넘어가기 (문제 해결, 데이터 전달 방법 비교) (0) | 2025.02.08 |
에러 발생 - 예상치 못한 데이터 값 발생 (0) | 2025.02.07 |