[UIKit] Spotify Clone: Library UI

Junyoung Park·2022년 9월 10일
1

UIKit

목록 보기
21/142
post-thumbnail

Building Spotify App in Swift 5 & UIKit - Part 21 - Library UI (Xcode 12, 2021, Swift 5) - Build App

Spotify Clone: Library UI

구현 목표

  • 스크롤 뷰의 자식 뷰 스크롤 기능
  • 토글 버튼 및 스크롤 인터렉션 구현

구현 태스크

  1. 스크롤 뷰 자식 뷰 등록하기
  2. 토글 버튼 클릭 → 델리게이트 통해 스크롤 뷰 변경
  3. 스크롤 오프셋 변경 → 델리게이트 통해 토글 버튼 변경

핵심 코드

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)
    }
}
  • 스크롤 뷰 내 플레이리스트 / 앨범 뷰 컨트롤러 두 개를 스크롤 가능하도록 표현하기 위한 자식 뷰 추가
  • UIScrollViewDelegatescrollViewDidScroll을 통해 현재 스크롤의 오프셋 감지 가능 → 스크롤 뷰에 등록한 플레이리스트 / 앨범 뷰 중 어느 뷰를 선택한지 감지 가능
  • 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 특유의 델리게이트 패턴에 보다 익숙해지자. 프로토콜을 통한 함수, 변수 값을 다른 뷰에서 조정/작동시키는 메커니즘.

profile
JUST DO IT

0개의 댓글