#41 Music Player 音樂播放器

進階版

APP 功能部分:

🌟 利用 AVPlayer 播放音樂

🌟 包含播放鍵,暫停鍵,下一首,上一首

🌟 調整音量

🌟 播完一首歌後,自動播放下一首歌

🌟 可滑動調整 & 顯示歌曲播放的時間

🌟 播放時間快進5秒、倒退5秒

🌟 背景播放音樂

🌟 重覆播放多首歌,單曲循環

🌟 隨機播放,順序播放

技術部分:

🌟 串接 iTunes API

🌟 UISearchBar

🌟 ViewController + CollectionView

🌟 AVPlayer()

🌟 prepare function

🌟 NotificationCenter

🌟 AVPlayer.Observing the Playback Time

輸入歌手搜尋音樂

想要做到的效果是:利用 UISearchBar 輸入歌手或團體,然後結合到 API get 的 function 的參數,去找出 iTunes 上符合的資料。

首先,要先讓 ViewController 繼承 UISearchBarDelegate。之後就可以使用它的 function ,例如:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
// 在此處處理搜索操作
}

說明:注意其內部參數 searchText ,使用者在輸入字串時被始用

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
// 在此處顯示搜索結果
}

說明:在使用者按下搜索時會執行這個 function。這裡只用到這個 function

extension SearchViewController: UISearchBarDelegate {

func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {

if searchBar.text != "" {
fetchMusic(term: searchBar.text ?? "")
view.endEditing(true)
collectionView.reloadData()
}
}
}

利用 AVPlayer 播放音樂、包含播放鍵、暫停鍵、下一首、上一首、隨機 button,點選將隨機播放一首歌、調整音量

可以參考基本版文章:

特別注意調整音量的部分,若是沒有特別設定一開使的音量則音量會是100%(就是1)。

希望一開始音量為50%,所以是設成0.5 (音量型別是Float,範圍是0~1)

播完一首歌後,自動重覆播放多首歌 or 單曲循環播放

運用到 NotificationCenter.default.addObserver,判斷Button的圖示決定要單曲播放或是下一首,搭配 AVPlayerItemDidPlayToEndTime 歌曲播放完的通知,寫在 viewDidLoad 裡

NotificationCenter.default.addObserver(forName: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil, queue: .main) { _ in

if self.repeatButton.imageView?.image == UIImage(systemName: "repeat") {
//自動播放下一首
self.player.pause()
self.index = (self.index + 1) % self.musics.count
self.currentTime = 0
self.playMusic()
} else if self.repeatButton.imageView?.image == UIImage(systemName: "repeat.1") {
self.player.pause()
self.currentTime = 0
self.playMusic()
}
}

Button 的 IBAction function

    @IBAction func pressRepeat(_ sender: Any) {
if repeatButton.imageView?.image == UIImage(systemName: "repeat") {
repeatButton.setImage(UIImage(systemName: "repeat.1"), for: .normal)
} else {
repeatButton.setImage(UIImage(systemName: "repeat"), for: .normal)
}
}

可滑動調整 & 顯示歌曲播放的時間

✨ Observing the Playback Time

func addPerioedTimeObserver() {

let timeScale = CMTimeScale(NSEC_PER_SEC)
let time = CMTime(seconds: 1, preferredTimescale: timeScale)

self.timeObserverToken = player.addPeriodicTimeObserver(forInterval: time, queue: .main, using: { _ in

self.currentTime = self.player.currentTime().seconds
self.timeConfiguration()

})
}

然後把function addPeriodTimeObserver()放在播放的 function 裡

注意:有時播放時 APP 會突然 crash,查了一下解決的方式就是加入這一行
,確保 currentTime 不會是 Nan 或 Infinite

guard !(currentTime.isNaN || currentTime.isInfinite) else {return}

✨ 用 timeControlStatus 讀取播放器狀態

✨ 用 currentItem?.asset.duration.seconds 讀取歌曲總秒數

✨ 用 currentTime().seconds 讀取目前播放到第幾秒

✨ 用 seek 找到歌曲播放進度

播放進度的 Slider 的 IBAction function

    //change process of song while sliding the slider
@IBAction func changeTimeSlider(_ sender: UISlider) {
let time = CMTime(value: CMTimeValue(sender.value), timescale: 1)
player.seek(to: time)
}

說明:透過 seek 當滑動 Slider 就可以找到對應的播放進度了

播放時間快進5秒、倒退5秒

同樣用 seek 就可以做到

    @IBAction func pressGoforward(_ sender: Any) {
let time = CMTime(value: Int64(timeSlider.value + 5), timescale: 1)
player.seek(to: time)
}

@IBAction func pressBackward(_ sender: Any) {
let time = CMTime(value: Int64(timeSlider.value - 5), timescale: 1)
player.seek(to: time)
}

隨機播放,順序播放

--

--