2024.04.22 - [◽️ Programming/T I L] - [ProJect 일지] 영화 예매 앱 만들기 (1)
ScrollView..
오늘 이 스크롤 뷰 때문에 새벽까지 진짜 오기로 달렸다.. 결국엔 적용시키는데 성공해서 너무 기쁘다.. 이제야 어느정도 스크롤 뷰가 어떻게 적용되는지 확실하게 알게 된 것 같아 늦었지만 뿌듯한 하루인 것 같다. 그래도 하루에 하나는 알고 가는 느낌이라..
오늘 참 손이 많이 갔던 스크롤뷰 먼저 적용하는 과정을 보면
먼저 스크롤 뷰를 넣어준 후 그 안에 요소들을 관리하기 수월하도록 UIView를 넣어준다.
그 후 이 뷰를 스크롤 뷰의 Content Layout Guide 에 사진과 같이 맞춰준 후
Frame Layout에 가로 길이가 동일하도록 수정한다. 이때 수치가 임의적으로 들어가있을 수 있으므로 0으로 맞춰주는 것이 필수!
그 이후 넣어준 UIView의 높이를 원하는 만큼 잡으면 그 지점의 마지막까지 스크롤이 가능해진다..
스크롤 뷰가 그냥 간단하게 다른 컴포넌트들과 마찬가지로 쉽게 넣어서 사용한다고 생각했던게 오산이었고 이 기회에 스크롤 뷰 사용법을 아주 확실하게 알 수 있었다.
새로운 API 데이터 호출
이제 스크롤 뷰가 됐으니 밑에 새로운 영화 목록들을 가져올 수 있도록 설정해 두자.
이전에 가져왔던 네트워킹 코드를 그대로 활용해 새로운 API 데이터를 가져오기 수월했다.
func fetchTopRatedMovies(completion: @escaping (Swift.Result<data, error="">) -> Void) {
guard let movieURL2 = URL(string: "<https://api.themoviedb.org/3/movie/top_rated>") else {
let error = NSError(domain: "InvalidURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid movie URL"])
completion(.failure(error))
return
}
var request = URLRequest(url: movieURL2)
request.httpMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("Bearer \\(apiKey)", forHTTPHeaderField: "Authorization")
var components = URLComponents(url: movieURL2, resolvingAgainstBaseURL: true)!
components.queryItems = [
URLQueryItem(name: "language", value: "ko-KR"),
URLQueryItem(name: "page", value: "1")
]
guard let url = components.url else {
let error = NSError(domain: "InvalidURL", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid movie URL"])
completion(.failure(error))
return
}
request.url = url
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let error = error {
completion(.failure(error))
return
}
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
let error = NSError(domain: "HTTPError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid HTTP response"])
completion(.failure(error))
return
}
guard let data = data else {
let error = NSError(domain: "InvalidData", code: -1, userInfo: [NSLocalizedDescriptionKey: "No data received"])
completion(.failure(error))
return
}
completion(.success(data))
}
task.resume()
}
</data,>
이와 같이 NetworkingManager에 새로운 데이터를 받을 수 있도록 연결하고
func fetchSecondaryData() {
netWorkingManager.fetchTopRatedMovies { [weak self] result in
switch result {
case .success(let data):
do {
let decoder = JSONDecoder()
self?.secondaryMovieData = try decoder.decode(Welcome.self, from: data)
DispatchQueue.main.async {
self?.subCollectionView.reloadData()
}
} catch {
print("\\(error)")
}
case .failure(let error):
print("\\(error)")
}
}
}
새로운 데이터 전달 메소드를 만들어 설정하면 동일하게 설정이 가능하다.
나는 이번에 컬렉션 뷰를 두개를 활용했기 때문에 새로운 컬렉션 뷰 셀을 만들어 연결해준 후 기존에 사용했던 collectionview datasource와 delegate를 그대로 사용할 수 있도록 if 문을 사용해 넣어주었다.
extension MainViewController: UICollectionViewDelegate, UICollectionViewDataSource {
// 첫번째 컬렉션 뷰 셀 갯수와 두번째 컬렉션 뷰 셀 갯수 설정
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if collectionView == mainCollectionView {
return movieData?.results.count ?? 0
} else if collectionView == subCollectionView {
return secondaryMovieData?.results.count ?? 0
}
return 0
}
이렇게 셀의 갯수를 각각 다른 컬렉션 뷰에 적용 될 수 있도록 넣어준 뒤
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if collectionView == mainCollectionView {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell", for: indexPath) as? MainCollectionViewCell else {
fatalError("Failed to dequeue MainCollectionViewCell")
}
if let movieData = movieData {
let movie = movieData.results[indexPath.item]
cell.collectionMainLabel.text = movie.title
let voteCount = movie.voteCount * 1000
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 0
if let formattedVoteCount = formatter.string(from: NSNumber(value: voteCount)) {
cell.collectionSubLabel.text = "\\(formattedVoteCount)명"
}
}
cell.collectionButton.layer.borderWidth = 1
cell.collectionButton.layer.borderColor = UIColor.systemIndigo.cgColor
cell.collectionButton.layer.cornerRadius = 15
if let movie = movieData?.results[indexPath.item] {
fetchImage(for: movie.posterPath) { image in
DispatchQueue.main.async {
cell.collectionMainImage.image = image
}
}
}
return cell
}
첫번째 셀에 원래대로 데이터를 넣어주고
else if collectionView == subCollectionView {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "UpRateViewCell", for: indexPath) as? UpRateCollectionViewCell else {
fatalError("Failed to dequeue SubCollectionViewCell")
}
if let movieData = secondaryMovieData {
let movie = movieData.results[indexPath.item]
cell.upRateCollectionMainLabel.text = movie.title
let voteCount = movie.voteCount * 1000
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 0
if let formattedVoteCount = formatter.string(from: NSNumber(value: voteCount)) {
cell.upRateCollectionSubLabel.text = "\\(formattedVoteCount)명"
}
}
cell.upRateButton.layer.borderWidth = 1
cell.upRateButton.layer.borderColor = UIColor.systemIndigo.cgColor
cell.upRateButton.layer.cornerRadius = 15
if let movie = secondaryMovieData?.results[indexPath.item] {
fetchImage(for: movie.posterPath) { image in
DispatchQueue.main.async {
cell.upRateCollectionImage.image = image
}
}
}
return cell
}
return UICollectionViewCell()
}
}
두번째 셀에도 첫번째 셀에 넣었던 데이터와 유사하게 넣어주니 각각 컬렉션 뷰에 해당하는 데이터가 딱 들어갔다.
이렇게 두번째 컬렉션 뷰 까지 넣기 성공!
관객수 설정하기
그리고 이제 데이터에는 천명 단위로 나와있는 관객 수를 직관적으로 볼 수 있도록 데이터 포맷을 넣어주어 변환하였다.
let voteCount = movie.voteCount * 1000
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 0
if let formattedVoteCount = formatter.string(from: NSNumber(value: voteCount)) {
cell.upRateCollectionSubLabel.text = "\\(formattedVoteCount)명"
}
이렇게 넣어주니 사진과 같이 제대로 잘 출력되는 것을 볼 수 있었다.
블로그에 작성한거 외에 이미지 추출에 성공한거랑 여러가지 등등 디테일하게 한건 있지만 새벽시간까지 스크롤뷰에 시달리느라 얼른 정리하고 자야겠다..
오늘은 여기까지.. 이제 메인의 디테일적인 부분을 좀 더 살려 완성도를 높히고 마무리한 뒤 얼른 로그인 구현해야지
'◽️ Programming > T I L' 카테고리의 다른 글
[ProJect 일지] 영화 예매 앱 만들기 (4) (0) | 2024.04.25 |
---|---|
[ProJect 일지] 영화 예매 앱 만들기 (3) (0) | 2024.04.24 |
[ProJect 일지] 영화 예매 앱 만들기 (1) (2) | 2024.04.22 |
Alamofire 활용하여 내 Github 만들기 (완) (1) | 2024.04.18 |
Alamofire 활용하여 내 Github 만들기 (1) (0) | 2024.04.17 |