이용한 라이브러리 : FSPagerView
https://github.com/WenchaoD/FSPagerView
.linear
를 이용한다sudo gem install cocoapods
pod --version
pod init
sudo vi Podfile
pod 'FSPagerView'
:wq
로 내용 저장 후, pod install
let pagerView = FSPagerView()
func settingPagerView() {
// 커스텀 셀 등록 (MainPagerViewCell 클래스는 밑에서 구현)
pagerView.register(MainPagerViewCell.self, forCellWithReuseIdentifier: MainPagerViewCell.description())
// 프로토콜 연결
pagerView.dataSource = self
pagerView.delegate = self
// 각종 설정
pagerView.isInfinite = true
pagerView.transformer = FSPagerViewTransformer(type: .linear)
// pagerView의 itemSize 설정
let bounds = UIScreen.main.bounds
pagerView.itemSize = CGSize(
width: bounds.height * 0.35,
height: bounds.height * 0.65
)
pagerView.interitemSpacing = 20
}
FSPagerViewCell
에 textLabel
과 imageView
객체가 있다. 앨범 커버를 띄우기 위해 imageView
를 이용했고, textLabel
은 따로 사용하지 않았다class MainPagerViewCell: FSPagerViewCell {
// 셀 내에 있는 버튼 클릭 액션을 프로토콜을 이용해서 전달한다 (아래에서 프로토콜 선언 예정)
var parentVC: PlayButtonActionProtocol?
/* ===== 객체 인스턴스 생성 ===== */
// 1. 앨범 커버 이미지 -> 기본 imageView 사용
// 2. 제목 레이블
let titleLabel = {...}
// 3. 아티스트 레이블
let artistLabel = {...}
// 4. 앨범 커버 위의 버튼 (투명)
// - 기본 imageView에 같은 크기의 투명한 버튼을 올렸다
lazy var playButton = {...}
// 5. 재생 / 정지 이미지
let playImageView = {...}
// 6. records 레이블
let recordLabel = {...}
// 7. records 레이블 위의 버튼 (투명)
// - 앨범 커버와 마찬가지로 같은 크기의 투명한 버튼을 올렸다
lazy var recordButton = {...}
// 8. 장르 레이블 in 스택뷰
let stackView: UIStackView = {...}
// 8. 장르 레이블
let genre1Label = {...}
let genre2Label = {...}
let genre3Label = {...}
// 9. 음악 재생 설명 레이블
let explainPlayLabel = {...}
@objc
func playButtonClicked() {
// 1. 갑자기 이미지 등장 (정지 or 재생)
// 2. 점점 흐려지면서 없어짐
if parentVC == nil { return }
// (프로토콜을 이용한 함수 실행)
parentVC?.play()
self.playImageView.image = UIImage(systemName: (parentVC?.isPlaying ?? false) ? "play.circle" : "pause.circle")
// 1.
self.playImageView.alpha = 1
// 2.
UIView.animate(withDuration: 1.5) {
self.playImageView.alpha = 0
} completion: { _ in
print("finish")
}
// (프로토콜을 이용한 값전달)
parentVC?.isPlaying.toggle()
}
@objc
func recordButtonClicked() {
// (프로토콜을 이용한 함수 실행)
parentVC?.showBottomSheet()
}
override func prepareForReuse() {
// 기본 imageView를 언제든지 커스텀 상태로 유지시킨다
self.imageView?.contentMode = .scaleAspectFit
self.imageView?.snp.makeConstraints { make in
make.top.horizontalEdges.equalTo(self).inset(12)
make.height.equalTo(imageView!.snp.width)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(titleLabel)
addSubview(artistLabel)
addSubview(playImageView)
addSubview(playButton)
addSubview(recordLabel)
addSubview(recordButton)
addSubview(stackView)
stackView.addArrangedSubview(genre1Label)
stackView.addArrangedSubview(genre2Label)
stackView.addArrangedSubview(genre3Label)
addSubview(explainPlayLabel)
if self.imageView == nil { return }
/* 레이아웃 코드는 생략 */
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func designCell(_ sender: MusicItemTable) {
// 인스턴스 객체들에 원하는 값을 넣어준다
if let str = sender.bigImageURL, let url = URL(string: str) {
self.imageView?.kf.setImage(with: url)
}
titleLabel.text = sender.name
artistLabel.text = sender.artist
recordLabel.text = (sender.count > 1) ? "\(sender.count) records" : "\(sender.count) record"
// ( 두 번째 인덱스 제외 ("음악") )
for (index, item) in [genre1Label, genre2Label, genre3Label].enumerated() {
item.isHidden = false
var genreIdx = index
if index >= 1 {
genreIdx = index + 1
}
if genreIdx <= sender.genres.count - 1 {
item.text = sender.genres[genreIdx]
} else {
item.isHidden = true
}
}
}
}
extension PagerViewController: FSPagerViewDelegate, FSPagerViewDataSource {
// 아이템의 개수
func numberOfItems(in pagerView: FSPagerView) -> Int {
return viewModel.numberOfItems()
}
// 셀 설정
func pagerView(_ pagerView: FSPagerView, cellForItemAt index: Int) -> FSPagerViewCell {
guard let cell = pagerView.dequeueReusableCell(withReuseIdentifier: MainPagerViewCell.description(), at: index) as? MainPagerViewCell else { return FSPagerViewCell() }
// index로 데이터 값을 받아오고, 그대로 셀 디자인에 사용한다
viewModel.cellForItemAt(index) { item in
cell.designCell(item)
}
cell.parentVC = self
return cell
}
// 선택 막기
func pagerView(_ pagerView: FSPagerView, shouldHighlightItemAt index: Int) -> Bool {
return false
}
// 다음 아이템으로 넘어갔을 때
func pagerViewDidEndDecelerating(_ pagerView: FSPagerView) {
// (음악을 멈추고, player를 교체하는 코드)
player.pause()
isPlaying = false
replacePlayer()
}
}
protocol PlayButtonActionProtocol: AnyObject {
// 셀 클래스 내의 버튼이 눌렸을 때 뷰컨트롤러 내에서 함수가 실행되게 하기 위함
var isPlaying: Bool { get set }
func play()
func showBottomSheet()
}