#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)
}
隨機播放,順序播放
參考資料: