Building Spotify App in Swift 5 & UIKit - Part 21 - Library UI (Xcode 12, 2021, Swift 5) - Build App
import UIKit
class LibraryViewController: UIViewController {
private let playlistVC = LibraryPlaylistsViewController()
private let albumsVC = LibraryAlbumsViewController()
private let scrollView: UIScrollView = {
let scrollView = UIScrollView()
scrollView.isPagingEnabled = true
return scrollView
}()
private let toggleView = LibraryToggleView()
...
private func setLibraryViewUI() {
...
scrollView.delegate = self
...
toggleView.delegate = self
addChildren()
}
private func addChildren() {
addChild(playlistVC)
addChild(albumsVC)
scrollView.addSubview(playlistVC.view)
scrollView.addSubview(albumsVC.view)
playlistVC.view.frame = CGRect(x: 0, y: 0, width: scrollView.width, height: scrollView.height)
albumsVC.view.frame = CGRect(x: view.width, y: 0, width: scrollView.width, height: scrollView.height)
playlistVC.didMove(toParent: self)
albumsVC.didMove(toParent: self)
}
}
extension LibraryViewController: UIScrollViewDelegate {
func scrollViewDidScroll(_ scrollView: UIScrollView) {
if scrollView.contentOffset.x >= (view.width-100) {
toggleView.update(for: .album)
} else {
toggleView.update(for: .playlist)
}
}
}
extension LibraryViewController: LibraryToggleViewDelegate {
func libraryToggleViewDidTapPlaylists(_ toggleView: LibraryToggleView) {
scrollView.setContentOffset(.zero, animated: true)
}
func libraryToggleViewDidTapAlbums(_ toggleView: LibraryToggleView) {
scrollView.setContentOffset(CGPoint(x: view.width, y: 0), animated: true)
}
}
UIScrollViewDelegate
의 scrollViewDidScroll
을 통해 현재 스크롤의 오프셋 감지 가능 → 스크롤 뷰에 등록한 플레이리스트 / 앨범 뷰 중 어느 뷰를 선택한지 감지 가능LibraryToggleViewDelegate
를 통해 토글 뷰의 토글 버튼 클릭 시 이벤트 사용 가능import UIKit
protocol LibraryToggleViewDelegate: AnyObject {
func libraryToggleViewDidTapPlaylists(_ toggleView: LibraryToggleView)
func libraryToggleViewDidTapAlbums(_ toggleView: LibraryToggleView)
}
class LibraryToggleView: UIView {
enum State {
case playlist
case album
}
private var state: State = .playlist
weak var delegate: LibraryToggleViewDelegate?
private let playlistButton: UIButton = {
// button UI
}()
private let albumsButton: UIButton = {
// button UI
}()
private let indicatorView: UIView = {
// indicator UI
}()
...
private func layoutIndicator() {
UIView.animate(withDuration: 0.2) {
switch self.state {
case .playlist:
self.indicatorView.frame = CGRect(x: 0, y: self.playlistButton.bottom, width: 100, height: 3)
case .album:
self.indicatorView.frame = CGRect(x: 100, y: self.playlistButton.bottom, width: 100, height: 3)
}
}
}
...
@objc private func didTapPlaylists() {
state = .playlist
delegate?.libraryToggleViewDidTapPlaylists(self)
layoutIndicator()
}
@objc private func didTapAlbums() {
state = .album
delegate?.libraryToggleViewDidTapAlbums(self)
layoutIndicator()
}
func update(for state: State) {
self.state = state
layoutIndicator()
}
}
LibraryToggleViewDelegate
사용 → LibraryViewController
가 현재 스크롤 상황에 따른 버튼 선택 가능하도록 함수 선택지를 제공layoutIndicator
: 인디케이터 값 변경을 애니메이션으로 표현두 개 이상의 뷰 간의 인터렉션(함수, 변수 사용)을 원활하게 하는 UIKit 특유의 델리게이트 패턴에 보다 익숙해지자. 프로토콜을 통한 함수, 변수 값을 다른 뷰에서 조정/작동시키는 메커니즘.